From a139d2b36da39fbfb018ef6973e9316a64a4ca6c Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Fri, 1 Jan 2021 07:31:54 -0500 Subject: 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. --- libqpdf/QPDFPageObjectHelper.cc | 108 ++++++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 25 deletions(-) (limited to 'libqpdf/QPDFPageObjectHelper.cc') 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 action, + std::function selector) +{ + QTC::TC("qpdf", "QPDFPageObjectHelper::forEachXObject", + recursive + ? (this->oh.isFormXObject() ? 0 : 1) + : (this->oh.isFormXObject() ? 2 : 3)); + std::set seen; + std::list 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 action) +{ + forEachXObject(recursive, action, + [](QPDFObjectHandle obj) { return obj.isImage(); }); +} + +void +QPDFPageObjectHelper::forEachFormXObject( + bool recursive, + std::function action) +{ + forEachXObject(recursive, action, + [](QPDFObjectHandle obj) { return obj.isFormXObject(); }); +} + std::map QPDFPageObjectHelper::getPageImages() { @@ -396,32 +463,23 @@ std::map QPDFPageObjectHelper::getImages() { std::map result; - QPDFObjectHandle resources = getAttribute("/Resources", false); - if (resources.isDictionary()) - { - if (resources.hasKey("/XObject")) - { - QPDFObjectHandle xobject = resources.getKey("/XObject"); - std::set keys = xobject.getKeys(); - for (std::set::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 +QPDFPageObjectHelper::getFormXObjects() +{ + std::map result; + forEachFormXObject(false, [&result](QPDFObjectHandle& obj, + QPDFObjectHandle&, + std::string const& key) { + result[key] = obj; + }); return result; } -- cgit v1.2.3-54-g00ecf