diff options
author | Jay Berkenbilt <ejb@ql.org> | 2021-01-01 13:31:54 +0100 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2021-01-02 18:29:31 +0100 |
commit | a139d2b36da39fbfb018ef6973e9316a64a4ca6c (patch) | |
tree | 6e7ea711324e717fba197d031550dfe7ae0f2f94 /libqpdf | |
parent | afb48d23a984ab1fe27a57ecbb3d56ac2e3a2099 (diff) | |
download | qpdf-a139d2b36da39fbfb018ef6973e9316a64a4ca6c.tar.zst |
Add several methods for working with form XObjects (fixes #436)
Make some more methods in QPDFPageObjectHelper work with form
XObjects, provide forEach methods to walk through nested form
XObjects, possibly recursively. This should make it easier to work
with form XObjects from user code.
Diffstat (limited to 'libqpdf')
-rw-r--r-- | libqpdf/QPDFObjectHandle.cc | 15 | ||||
-rw-r--r-- | libqpdf/QPDFPageObjectHelper.cc | 108 |
2 files changed, 98 insertions, 25 deletions
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 180ccfa3..add0b14d 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2948,6 +2948,21 @@ QPDFObjectHandle::isFormXObject() ("/Form" == dict.getKey("/Subtype").getName())); } +bool +QPDFObjectHandle::isImage(bool exclude_imagemask) +{ + if (! this->isStream()) + { + return false; + } + QPDFObjectHandle dict = this->getDict(); + return (dict.hasKey("/Subtype") && + (dict.getKey("/Subtype").getName() == "/Image") && + ((! exclude_imagemask) || + (! (dict.getKey("/ImageMask").isBool() && + dict.getKey("/ImageMask").getBoolValue())))); +} + void QPDFObjectHandle::assertPageObject() { diff --git a/libqpdf/QPDFPageObjectHelper.cc b/libqpdf/QPDFPageObjectHelper.cc index ce244253..ef563dc2 100644 --- a/libqpdf/QPDFPageObjectHelper.cc +++ b/libqpdf/QPDFPageObjectHelper.cc @@ -386,6 +386,73 @@ QPDFPageObjectHelper::getMediaBox(bool copy_if_shared) return getAttribute("/MediaBox", copy_if_shared); } +void +QPDFPageObjectHelper::forEachXObject( + bool recursive, + std::function<void(QPDFObjectHandle& obj, + QPDFObjectHandle& xobj_dict, + std::string const& key)> action, + std::function<bool(QPDFObjectHandle)> selector) +{ + QTC::TC("qpdf", "QPDFPageObjectHelper::forEachXObject", + recursive + ? (this->oh.isFormXObject() ? 0 : 1) + : (this->oh.isFormXObject() ? 2 : 3)); + std::set<QPDFObjGen> seen; + std::list<QPDFPageObjectHelper> queue; + queue.push_back(*this); + while (! queue.empty()) + { + QPDFPageObjectHelper ph = queue.front(); + queue.pop_front(); + QPDFObjGen og = ph.oh.getObjGen(); + if (seen.count(og)) + { + continue; + } + seen.insert(og); + QPDFObjectHandle resources = ph.getAttribute("/Resources", false); + if (resources.isDictionary() && resources.hasKey("/XObject")) + { + QPDFObjectHandle xobj_dict = resources.getKey("/XObject"); + for (auto const& key: xobj_dict.getKeys()) + { + QPDFObjectHandle obj = xobj_dict.getKey(key); + if ((! selector) || selector(obj)) + { + action(obj, xobj_dict, key); + } + if (recursive && obj.isFormXObject()) + { + queue.push_back(QPDFPageObjectHelper(obj)); + } + } + } + } +} + +void +QPDFPageObjectHelper::forEachImage( + bool recursive, + std::function<void(QPDFObjectHandle& obj, + QPDFObjectHandle& xobj_dict, + std::string const& key)> action) +{ + forEachXObject(recursive, action, + [](QPDFObjectHandle obj) { return obj.isImage(); }); +} + +void +QPDFPageObjectHelper::forEachFormXObject( + bool recursive, + std::function<void(QPDFObjectHandle& obj, + QPDFObjectHandle& xobj_dict, + std::string const& key)> action) +{ + forEachXObject(recursive, action, + [](QPDFObjectHandle obj) { return obj.isFormXObject(); }); +} + std::map<std::string, QPDFObjectHandle> QPDFPageObjectHelper::getPageImages() { @@ -396,32 +463,23 @@ std::map<std::string, QPDFObjectHandle> QPDFPageObjectHelper::getImages() { std::map<std::string, QPDFObjectHandle> result; - QPDFObjectHandle resources = getAttribute("/Resources", false); - if (resources.isDictionary()) - { - if (resources.hasKey("/XObject")) - { - QPDFObjectHandle xobject = resources.getKey("/XObject"); - std::set<std::string> keys = xobject.getKeys(); - for (std::set<std::string>::iterator iter = keys.begin(); - iter != keys.end(); ++iter) - { - std::string key = (*iter); - QPDFObjectHandle value = xobject.getKey(key); - if (value.isStream()) - { - QPDFObjectHandle dict = value.getDict(); - if (dict.hasKey("/Subtype") && - (dict.getKey("/Subtype").getName() == "/Image") && - (! dict.hasKey("/ImageMask"))) - { - result[key] = value; - } - } - } - } - } + forEachImage(false, [&result](QPDFObjectHandle& obj, + QPDFObjectHandle&, + std::string const& key) { + result[key] = obj; + }); + return result; +} +std::map<std::string, QPDFObjectHandle> +QPDFPageObjectHelper::getFormXObjects() +{ + std::map<std::string, QPDFObjectHandle> result; + forEachFormXObject(false, [&result](QPDFObjectHandle& obj, + QPDFObjectHandle&, + std::string const& key) { + result[key] = obj; + }); return result; } |