mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 13:17:35 +00:00
LibPDF: Implement StitchingFunction creation
This commit is contained in:
parent
a3399fa13a
commit
ba34ddeb21
2 changed files with 88 additions and 1 deletions
|
@ -22,6 +22,7 @@
|
||||||
X(BaseFont) \
|
X(BaseFont) \
|
||||||
X(BitsPerComponent) \
|
X(BitsPerComponent) \
|
||||||
X(BlackPoint) \
|
X(BlackPoint) \
|
||||||
|
X(Bounds) \
|
||||||
X(C) \
|
X(C) \
|
||||||
X(C0) \
|
X(C0) \
|
||||||
X(C1) \
|
X(C1) \
|
||||||
|
@ -59,6 +60,7 @@
|
||||||
X(Differences) \
|
X(Differences) \
|
||||||
X(Domain) \
|
X(Domain) \
|
||||||
X(E) \
|
X(E) \
|
||||||
|
X(Encode) \
|
||||||
X(Encoding) \
|
X(Encoding) \
|
||||||
X(Encrypt) \
|
X(Encrypt) \
|
||||||
X(EncryptMetadata) \
|
X(EncryptMetadata) \
|
||||||
|
@ -83,6 +85,7 @@
|
||||||
X(FontFile2) \
|
X(FontFile2) \
|
||||||
X(FontFile3) \
|
X(FontFile3) \
|
||||||
X(FunctionType) \
|
X(FunctionType) \
|
||||||
|
X(Functions) \
|
||||||
X(Gamma) \
|
X(Gamma) \
|
||||||
X(H) \
|
X(H) \
|
||||||
X(Height) \
|
X(Height) \
|
||||||
|
|
|
@ -122,9 +122,92 @@ PDFErrorOr<ReadonlySpan<float>> ExponentialInterpolationFunction::evaluate(Reado
|
||||||
|
|
||||||
class StitchingFunction final : public Function {
|
class StitchingFunction final : public Function {
|
||||||
public:
|
public:
|
||||||
|
static PDFErrorOr<NonnullRefPtr<StitchingFunction>> create(Document*, Vector<Bound> domain, Optional<Vector<Bound>> range, NonnullRefPtr<DictObject>);
|
||||||
virtual PDFErrorOr<ReadonlySpan<float>> evaluate(ReadonlySpan<float>) const override;
|
virtual PDFErrorOr<ReadonlySpan<float>> evaluate(ReadonlySpan<float>) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StitchingFunction(Vector<NonnullRefPtr<Function>>);
|
||||||
|
|
||||||
|
Bound m_domain;
|
||||||
|
Optional<Vector<Bound>> m_range;
|
||||||
|
|
||||||
|
Vector<NonnullRefPtr<Function>> m_functions;
|
||||||
|
Vector<float> m_bounds;
|
||||||
|
Vector<Bound> m_encode;
|
||||||
|
Vector<float> mutable m_result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StitchingFunction::StitchingFunction(Vector<NonnullRefPtr<Function>> functions)
|
||||||
|
: m_functions(move(functions))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFErrorOr<NonnullRefPtr<StitchingFunction>>
|
||||||
|
StitchingFunction::create(Document* document, Vector<Bound> domain, Optional<Vector<Bound>> range, NonnullRefPtr<DictObject> dict)
|
||||||
|
{
|
||||||
|
if (domain.size() != 1)
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching requires domain with 1 entry" };
|
||||||
|
|
||||||
|
// "TABLE 3.38 Additional entries specific to a type 3 function dictionary"
|
||||||
|
|
||||||
|
if (!dict->contains(CommonNames::Functions))
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching requires /Functions" };
|
||||||
|
auto functions_array = TRY(dict->get_array(document, CommonNames::Functions));
|
||||||
|
|
||||||
|
Vector<NonnullRefPtr<Function>> functions;
|
||||||
|
for (size_t i = 0; i < functions_array->size(); i++) {
|
||||||
|
auto function = TRY(Function::create(document, functions_array->get_object_at(i)));
|
||||||
|
functions.append(move(function));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (functions.is_empty())
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching requires at least one function" };
|
||||||
|
|
||||||
|
if (!dict->contains(CommonNames::Bounds))
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching requires /Bounds" };
|
||||||
|
auto bounds_array = TRY(dict->get_array(document, CommonNames::Bounds));
|
||||||
|
|
||||||
|
if (bounds_array->size() != functions.size() - 1)
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching /Bounds size does not match /Functions size" };
|
||||||
|
|
||||||
|
Vector<float> bounds;
|
||||||
|
for (size_t i = 0; i < bounds_array->size(); i++) {
|
||||||
|
bounds.append(bounds_array->at(i).to_float());
|
||||||
|
if (i > 0 && bounds[i - 1] >= bounds[i])
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching /Bounds not strictly increasing" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bounds.is_empty()) {
|
||||||
|
if (domain[0].lower == domain[0].upper)
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching /Bounds requires non-zero domain" };
|
||||||
|
if (domain[0].lower >= bounds[0] || bounds.last() >= domain[0].upper)
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching /Bounds out of domain" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dict->contains(CommonNames::Encode))
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching requires /Encode" };
|
||||||
|
auto encode_array = TRY(dict->get_array(document, CommonNames::Encode));
|
||||||
|
|
||||||
|
if (encode_array->size() != functions.size() * 2)
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching /Encode size does not match /Functions size" };
|
||||||
|
|
||||||
|
Vector<Bound> encode;
|
||||||
|
for (size_t i = 0; i < encode_array->size(); i += 2) {
|
||||||
|
encode.append({ encode_array->at(i).to_float(), encode_array->at(i + 1).to_float() });
|
||||||
|
if (encode.last().lower > encode.last().upper)
|
||||||
|
return Error { Error::Type::MalformedPDF, "Function stitching /Encode lower bound > upper bound" };
|
||||||
|
}
|
||||||
|
|
||||||
|
auto function = adopt_ref(*new StitchingFunction(move(functions)));
|
||||||
|
function->m_domain = domain[0];
|
||||||
|
function->m_range = move(range);
|
||||||
|
function->m_bounds = move(bounds);
|
||||||
|
function->m_encode = move(encode);
|
||||||
|
if (function->m_range.has_value())
|
||||||
|
function->m_result.resize(function->m_range.value().size());
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
PDFErrorOr<ReadonlySpan<float>> StitchingFunction::evaluate(ReadonlySpan<float>) const
|
PDFErrorOr<ReadonlySpan<float>> StitchingFunction::evaluate(ReadonlySpan<float>) const
|
||||||
{
|
{
|
||||||
return Error(Error::Type::RenderingUnsupported, "StitchingFunction not yet implemented"_string);
|
return Error(Error::Type::RenderingUnsupported, "StitchingFunction not yet implemented"_string);
|
||||||
|
@ -715,7 +798,8 @@ PDFErrorOr<NonnullRefPtr<Function>> Function::create(Document* document, Nonnull
|
||||||
// FIXME: spec is not clear on if this should work with a StreamObject.
|
// FIXME: spec is not clear on if this should work with a StreamObject.
|
||||||
return ExponentialInterpolationFunction::create(document, move(domain), move(optional_range), function_dict);
|
return ExponentialInterpolationFunction::create(document, move(domain), move(optional_range), function_dict);
|
||||||
case 3:
|
case 3:
|
||||||
return adopt_ref(*new StitchingFunction());
|
// FIXME: spec is not clear on if this should work with a StreamObject.
|
||||||
|
return StitchingFunction::create(document, move(domain), move(optional_range), function_dict);
|
||||||
case 4:
|
case 4:
|
||||||
if (!object->is<StreamObject>())
|
if (!object->is<StreamObject>())
|
||||||
return Error { Error::Type::MalformedPDF, "Function type 4 requires stream object" };
|
return Error { Error::Type::MalformedPDF, "Function type 4 requires stream object" };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue