mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 15:17:36 +00:00
LibPDF: Implement Fuction::create()
This commit is contained in:
parent
b78ea81de5
commit
1aed465efe
2 changed files with 65 additions and 2 deletions
|
@ -55,6 +55,7 @@
|
||||||
X(DeviceN) \
|
X(DeviceN) \
|
||||||
X(DeviceRGB) \
|
X(DeviceRGB) \
|
||||||
X(Differences) \
|
X(Differences) \
|
||||||
|
X(Domain) \
|
||||||
X(E) \
|
X(E) \
|
||||||
X(Encoding) \
|
X(Encoding) \
|
||||||
X(Encrypt) \
|
X(Encrypt) \
|
||||||
|
@ -79,6 +80,7 @@
|
||||||
X(FontFile) \
|
X(FontFile) \
|
||||||
X(FontFile2) \
|
X(FontFile2) \
|
||||||
X(FontFile3) \
|
X(FontFile3) \
|
||||||
|
X(FunctionType) \
|
||||||
X(Gamma) \
|
X(Gamma) \
|
||||||
X(H) \
|
X(H) \
|
||||||
X(Height) \
|
X(Height) \
|
||||||
|
|
|
@ -4,12 +4,20 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <LibPDF/CommonNames.h>
|
||||||
|
#include <LibPDF/Document.h>
|
||||||
#include <LibPDF/Function.h>
|
#include <LibPDF/Function.h>
|
||||||
|
#include <LibPDF/ObjectDerivatives.h>
|
||||||
|
|
||||||
// PDF 1.7 spec, 3.9 Functions
|
// PDF 1.7 spec, 3.9 Functions
|
||||||
|
|
||||||
namespace PDF {
|
namespace PDF {
|
||||||
|
|
||||||
|
struct Bound {
|
||||||
|
float lower;
|
||||||
|
float upper;
|
||||||
|
};
|
||||||
|
|
||||||
class SampledFunction final : public Function {
|
class SampledFunction final : public Function {
|
||||||
public:
|
public:
|
||||||
virtual PDFErrorOr<ReadonlySpan<float>> evaluate(ReadonlySpan<float>) const override;
|
virtual PDFErrorOr<ReadonlySpan<float>> evaluate(ReadonlySpan<float>) const override;
|
||||||
|
@ -50,9 +58,62 @@ PDFErrorOr<ReadonlySpan<float>> PostScriptCalculatorFunction::evaluate(ReadonlyS
|
||||||
return Error(Error::Type::RenderingUnsupported, "PostScriptCalculatorFunction not yet implemented"_string);
|
return Error(Error::Type::RenderingUnsupported, "PostScriptCalculatorFunction not yet implemented"_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFErrorOr<NonnullRefPtr<Function>> Function::create(Document*, NonnullRefPtr<Object>)
|
PDFErrorOr<NonnullRefPtr<Function>> Function::create(Document* document, NonnullRefPtr<Object> object)
|
||||||
{
|
{
|
||||||
return Error(Error::Type::RenderingUnsupported, "Function creation not yet implemented"_string);
|
if (!object->is<DictObject>() && !object->is<StreamObject>())
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function object must be dict or stream" };
|
||||||
|
|
||||||
|
auto function_dict = object->is<DictObject>() ? object->cast<DictObject>() : object->cast<StreamObject>()->dict();
|
||||||
|
|
||||||
|
// "TABLE 3.35 Entries common to all function dictionaries"
|
||||||
|
|
||||||
|
if (!function_dict->contains(CommonNames::FunctionType))
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function requires /FunctionType" };
|
||||||
|
auto function_type = TRY(document->resolve_to<int>(function_dict->get_value(CommonNames::FunctionType)));
|
||||||
|
|
||||||
|
if (!function_dict->contains(CommonNames::Domain))
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function requires /Domain" };
|
||||||
|
auto domain_array = TRY(function_dict->get_array(document, CommonNames::Domain));
|
||||||
|
if (domain_array->size() % 2 != 0)
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function /Domain size not multiple of 2" };
|
||||||
|
|
||||||
|
Vector<Bound> domain;
|
||||||
|
for (size_t i = 0; i < domain_array->size(); i += 2) {
|
||||||
|
domain.append({ domain_array->at(i).to_float(), domain_array->at(i + 1).to_float() });
|
||||||
|
if (domain.last().lower > domain.last().upper)
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function /Domain lower bound > upper bound" };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't use PDFErrorOr with Optional::map()
|
||||||
|
Optional<Vector<Bound>> optional_range;
|
||||||
|
if (function_dict->contains(CommonNames::Range)) {
|
||||||
|
auto range_array = TRY(function_dict->get_array(document, CommonNames::Range));
|
||||||
|
if (range_array->size() % 2 != 0)
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function /Range size not multiple of 2" };
|
||||||
|
|
||||||
|
Vector<Bound> range;
|
||||||
|
for (size_t i = 0; i < range_array->size(); i += 2) {
|
||||||
|
range.append({ range_array->at(i).to_float(), range_array->at(i + 1).to_float() });
|
||||||
|
if (range.last().lower > range.last().upper)
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function /Range lower bound > upper bound" };
|
||||||
|
}
|
||||||
|
optional_range = move(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (function_type) {
|
||||||
|
case 0:
|
||||||
|
return adopt_ref(*new SampledFunction());
|
||||||
|
// The spec has no entry for `1`.
|
||||||
|
case 2:
|
||||||
|
return adopt_ref(*new ExponentialInterpolationFunction());
|
||||||
|
case 3:
|
||||||
|
return adopt_ref(*new StitchingFunction());
|
||||||
|
case 4:
|
||||||
|
return adopt_ref(*new PostScriptCalculatorFunction());
|
||||||
|
default:
|
||||||
|
dbgln("invalid function type {}", function_type);
|
||||||
|
return Error(Error::Type::MalformedPDF, "Function has unkonwn type"_string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue