diff --git a/include/qpdf/QPDFPageObjectHelper.hh b/include/qpdf/QPDFPageObjectHelper.hh index 9f1addd2..e6f9f76d 100644 --- a/include/qpdf/QPDFPageObjectHelper.hh +++ b/include/qpdf/QPDFPageObjectHelper.hh @@ -32,6 +32,10 @@ class QPDFPageObjectHelper: public QPDFObjectHelper { + // This is a helper class for page objects, but as of qpdf 10.1, + // many of the methods also work for form XObjects. When this is + // the case, it is noted in the comment. + public: QPDF_DLL QPDFPageObjectHelper(QPDFObjectHandle); @@ -40,14 +44,15 @@ class QPDFPageObjectHelper: public QPDFObjectHelper { } - // Return the effective value of this attribute for the page. If - // the requested attribute is not present on the page but is + // Works with pages and form XObjects. Return the effective value + // of this attribute for the page/form XObject. For pages, if the + // requested attribute is not present on the page but is // inheritable, look up through the page's ancestors in the page // tree. If copy_if_shared is true, then this method will replace // the attribute with a shallow copy if it is in indirect or // inherited and return the copy. You should do this if you are // going to modify the returned object and want the modifications - // to apply to the current page only. + // to apply to the current page/form XObject only. QPDF_DLL QPDFObjectHandle getAttribute(std::string const& name, bool copy_if_shared); @@ -70,7 +75,8 @@ class QPDFPageObjectHelper: public QPDFObjectHelper // Returns an empty map if there are no images or no resources. // Prior to qpdf 8.4.0, this function did not support inherited // resources, but it does now. Return value is a map from XObject - // name to the image object, which is always a stream. + // name to the image object, which is always a stream. Works with + // form XObjects as well as pages. QPDF_DLL std::map getPageImages(); diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 181793f4..d5d199d9 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -1320,35 +1320,7 @@ QPDFObjectHandle::getGeneration() const std::map QPDFObjectHandle::getPageImages() { - std::map result; - QPDFObjectHandle resources = - QPDFPageObjectHelper(*this).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; - } - } - } - } - } - - return result; + return QPDFPageObjectHelper(*this).getPageImages(); } std::vector diff --git a/libqpdf/QPDFPageObjectHelper.cc b/libqpdf/QPDFPageObjectHelper.cc index a80ab641..0e9792a6 100644 --- a/libqpdf/QPDFPageObjectHelper.cc +++ b/libqpdf/QPDFPageObjectHelper.cc @@ -314,33 +314,46 @@ QPDFObjectHandle QPDFPageObjectHelper::getAttribute(std::string const& name, bool copy_if_shared) { - bool inheritable = ((name == "/MediaBox") || (name == "/CropBox") || - (name == "/Resources") || (name == "/Rotate")); - - QPDFObjectHandle node = this->oh; - QPDFObjectHandle result(node.getKey(name)); - std::set seen; + QPDFObjectHandle result; + QPDFObjectHandle dict; + bool is_form_xobject = this->oh.isFormXObject(); bool inherited = false; - while (inheritable && result.isNull() && node.hasKey("/Parent")) + if (is_form_xobject) { - seen.insert(node.getObjGen()); - node = node.getKey("/Parent"); - if (seen.count(node.getObjGen())) - { - break; - } + dict = this->oh.getDict(); + result = dict.getKey(name); + } + else + { + dict = this->oh; + bool inheritable = ((name == "/MediaBox") || (name == "/CropBox") || + (name == "/Resources") || (name == "/Rotate")); + + QPDFObjectHandle node = dict; result = node.getKey(name); - if (! result.isNull()) + std::set seen; + while (inheritable && result.isNull() && node.hasKey("/Parent")) { - QTC::TC("qpdf", "QPDFPageObjectHelper non-trivial inheritance"); - inherited = true; + seen.insert(node.getObjGen()); + node = node.getKey("/Parent"); + if (seen.count(node.getObjGen())) + { + break; + } + result = node.getKey(name); + if (! result.isNull()) + { + QTC::TC("qpdf", "QPDFPageObjectHelper non-trivial inheritance"); + inherited = true; + } } } if (copy_if_shared && (inherited || result.isIndirect())) { - QTC::TC("qpdf", "QPDFPageObjectHelper copy shared attribute"); + QTC::TC("qpdf", "QPDFPageObjectHelper copy shared attribute", + is_form_xobject ? 0 : 1); result = result.shallowCopy(); - this->oh.replaceKey(name, result); + dict.replaceKey(name, result); } return result; } @@ -376,7 +389,34 @@ QPDFPageObjectHelper::getMediaBox(bool copy_if_shared) std::map QPDFPageObjectHelper::getPageImages() { - return this->oh.getPageImages(); + 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; + } + } + } + } + } + + return result; } void @@ -571,13 +611,8 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper( removeUnreferencedResourcesHelper( resource.getDict(), seen, [&resource]() { - auto result = resource.getDict().getKey("/Resources"); - if (result.isDictionary()) - { - result = result.shallowCopy(); - resource.getDict().replaceKey("/Resources", result); - } - return result; + return QPDFPageObjectHelper(resource) + .getAttribute("/Resources", true); }, [&resource](QPDFObjectHandle::TokenFilter* f) { resource.filterAsContents(f); diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 04e3e044..2fddc87c 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -422,7 +422,7 @@ QPDFFormFieldObjectHelper create AP from scratch 0 QPDFFormFieldObjectHelper replaced BMC at EOF 0 QPDFFormFieldObjectHelper fallback Tf 0 QPDFPageObjectHelper non-trivial inheritance 0 -QPDFPageObjectHelper copy shared attribute 0 +QPDFPageObjectHelper copy shared attribute 1 qpdf from_nr from repeat_nr 0 QPDF resolve duplicated page object 0 QPDF handle direct page object 0