aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2020-12-31 17:38:27 +0100
committerJay Berkenbilt <ejb@ql.org>2021-01-02 17:33:36 +0100
commite7a85545639d6d09923abb8fb300dda5889b110b (patch)
treea8c103f6ce911ef53a954c10d1de4c569beb9281
parent1562d34c096424b4916be09e8dcd2f0f3effb17f (diff)
downloadqpdf-e7a85545639d6d09923abb8fb300dda5889b110b.tar.zst
QPDFPageObjectHelper::getPageImages: support form XObjects
-rw-r--r--include/qpdf/QPDFPageObjectHelper.hh14
-rw-r--r--libqpdf/QPDFObjectHandle.cc30
-rw-r--r--libqpdf/QPDFPageObjectHelper.cc87
-rw-r--r--qpdf/qpdf.testcov2
4 files changed, 73 insertions, 60 deletions
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<std::string, QPDFObjectHandle> 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<std::string, QPDFObjectHandle>
QPDFObjectHandle::getPageImages()
{
- std::map<std::string, QPDFObjectHandle> result;
- QPDFObjectHandle resources =
- QPDFPageObjectHelper(*this).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;
- }
- }
- }
- }
- }
-
- return result;
+ return QPDFPageObjectHelper(*this).getPageImages();
}
std::vector<QPDFObjectHandle>
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<QPDFObjGen> 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<QPDFObjGen> 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<std::string, QPDFObjectHandle>
QPDFPageObjectHelper::getPageImages()
{
- return this->oh.getPageImages();
+ 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;
+ }
+ }
+ }
+ }
+ }
+
+ 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