LibPDF: Allow optional inheritable page attributes

Previously, get_inheritable_object would always try to find the object
and throw an error if it couldn't. The spec tells us that some page
attributes, like CropBox, are optional but also inheritable. Others,
like the media box and resources, are technically required by the spec,
but omitted by some documents.

In both cases, we are now able to search for inheritable objects and
find a suitable replacement if there wasn't one.
This commit is contained in:
Julian Offenhäuser 2023-03-24 22:07:03 +01:00 committed by Andrew Kaster
parent 320f5f91ab
commit fde990ead8
Notes: sideshowbarker 2024-07-17 17:38:29 +09:00
2 changed files with 37 additions and 15 deletions

View file

@ -109,26 +109,46 @@ PDFErrorOr<Page> Document::get_page(u32 index)
auto page_object = TRY(get_or_load_value(page_object_index)); auto page_object = TRY(get_or_load_value(page_object_index));
auto raw_page_object = TRY(resolve_to<DictObject>(page_object)); auto raw_page_object = TRY(resolve_to<DictObject>(page_object));
auto resources = TRY(get_inheritable_object(CommonNames::Resources, raw_page_object))->cast<DictObject>(); RefPtr<DictObject> resources;
auto maybe_resources_object = TRY(get_inheritable_object(CommonNames::Resources, raw_page_object));
if (maybe_resources_object.has_value())
resources = maybe_resources_object.value()->cast<DictObject>();
else
resources = adopt_ref(*new DictObject({}));
auto contents = TRY(raw_page_object->get_object(this, CommonNames::Contents)); auto contents = TRY(raw_page_object->get_object(this, CommonNames::Contents));
auto media_box_array = TRY(get_inheritable_object(CommonNames::MediaBox, raw_page_object))->cast<ArrayObject>(); Rectangle media_box;
auto media_box = Rectangle { auto maybe_media_box_object = TRY(get_inheritable_object(CommonNames::MediaBox, raw_page_object));
media_box_array->at(0).to_float(), if (maybe_media_box_object.has_value()) {
media_box_array->at(1).to_float(), auto media_box_array = maybe_media_box_object.value()->cast<ArrayObject>();
media_box_array->at(2).to_float(), media_box = Rectangle {
media_box_array->at(3).to_float(), media_box_array->at(0).to_float(),
}; media_box_array->at(1).to_float(),
media_box_array->at(2).to_float(),
media_box_array->at(3).to_float(),
};
} else {
// As most other libraries seem to do, we default to the standard
// US letter size of 8.5" x 11" (612 x 792 Postscript units).
media_box = Rectangle {
0, 0,
612, 792
};
}
auto crop_box = media_box; Rectangle crop_box;
if (raw_page_object->contains(CommonNames::CropBox)) { auto maybe_crop_box_object = TRY(get_inheritable_object(CommonNames::CropBox, raw_page_object));
auto crop_box_array = TRY(raw_page_object->get_array(this, CommonNames::CropBox)); if (maybe_crop_box_object.has_value()) {
auto crop_box_array = maybe_crop_box_object.value()->cast<ArrayObject>();
crop_box = Rectangle { crop_box = Rectangle {
crop_box_array->at(0).to_float(), crop_box_array->at(0).to_float(),
crop_box_array->at(1).to_float(), crop_box_array->at(1).to_float(),
crop_box_array->at(2).to_float(), crop_box_array->at(2).to_float(),
crop_box_array->at(3).to_float(), crop_box_array->at(3).to_float(),
}; };
} else {
crop_box = media_box;
} }
float user_unit = 1.0f; float user_unit = 1.0f;
@ -141,7 +161,7 @@ PDFErrorOr<Page> Document::get_page(u32 index)
VERIFY(rotate % 90 == 0); VERIFY(rotate % 90 == 0);
} }
Page page { move(resources), move(contents), media_box, crop_box, user_unit, rotate }; Page page { resources.release_nonnull(), move(contents), media_box, crop_box, user_unit, rotate };
m_pages.set(index, page); m_pages.set(index, page);
return page; return page;
} }
@ -306,13 +326,15 @@ PDFErrorOr<Destination> Document::create_destination_from_parameters(NonnullRefP
return Destination { type, page_number_by_index_ref.get(page_ref.as_ref_index()), parameters }; return Destination { type, page_number_by_index_ref.get(page_ref.as_ref_index()), parameters };
} }
PDFErrorOr<NonnullRefPtr<Object>> Document::get_inheritable_object(DeprecatedFlyString const& name, NonnullRefPtr<DictObject> object) PDFErrorOr<Optional<NonnullRefPtr<Object>>> Document::get_inheritable_object(DeprecatedFlyString const& name, NonnullRefPtr<DictObject> object)
{ {
if (!object->contains(name)) { if (!object->contains(name)) {
if (!object->contains(CommonNames::Parent))
return { OptionalNone() };
auto parent = TRY(object->get_dict(this, CommonNames::Parent)); auto parent = TRY(object->get_dict(this, CommonNames::Parent));
return get_inheritable_object(name, parent); return get_inheritable_object(name, parent);
} }
return object->get_object(this, name); return TRY(object->get_object(this, name));
} }
PDFErrorOr<Destination> Document::create_destination_from_dictionary_entry(NonnullRefPtr<Object> const& entry, HashMap<u32, u32> const& page_number_by_index_ref) PDFErrorOr<Destination> Document::create_destination_from_dictionary_entry(NonnullRefPtr<Object> const& entry, HashMap<u32, u32> const& page_number_by_index_ref)

View file

@ -143,7 +143,7 @@ private:
PDFErrorOr<Destination> create_destination_from_parameters(NonnullRefPtr<ArrayObject>, HashMap<u32, u32> const&); PDFErrorOr<Destination> create_destination_from_parameters(NonnullRefPtr<ArrayObject>, HashMap<u32, u32> const&);
PDFErrorOr<Destination> create_destination_from_dictionary_entry(NonnullRefPtr<Object> const& entry, HashMap<u32, u32> const& page_number_by_index_ref); PDFErrorOr<Destination> create_destination_from_dictionary_entry(NonnullRefPtr<Object> const& entry, HashMap<u32, u32> const& page_number_by_index_ref);
PDFErrorOr<NonnullRefPtr<Object>> get_inheritable_object(DeprecatedFlyString const& name, NonnullRefPtr<DictObject>); PDFErrorOr<Optional<NonnullRefPtr<Object>>> get_inheritable_object(DeprecatedFlyString const& name, NonnullRefPtr<DictObject>);
PDFErrorOr<NonnullRefPtr<Object>> find_in_name_tree(NonnullRefPtr<DictObject> root, DeprecatedFlyString name); PDFErrorOr<NonnullRefPtr<Object>> find_in_name_tree(NonnullRefPtr<DictObject> root, DeprecatedFlyString name);
PDFErrorOr<NonnullRefPtr<Object>> find_in_name_tree_nodes(NonnullRefPtr<ArrayObject> siblings, DeprecatedFlyString name); PDFErrorOr<NonnullRefPtr<Object>> find_in_name_tree_nodes(NonnullRefPtr<ArrayObject> siblings, DeprecatedFlyString name);