aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2019-01-25 12:55:31 +0100
committerJay Berkenbilt <ejb@ql.org>2019-01-26 04:30:05 +0100
commit009767d97a0dfebbb9bb71efb4b894b25fb59dd8 (patch)
tree6c10e6a67ecee41f511d06e88626f10bb737106a /libqpdf
parent2d32f4db8fd125f2481ecf767d9f6506e80481f6 (diff)
downloadqpdf-009767d97a0dfebbb9bb71efb4b894b25fb59dd8.tar.zst
Handle inheritable page attributes
Add getAttribute for handling inheritable page attributes, and fix getPageImages and annotation flattening code to use it.
Diffstat (limited to 'libqpdf')
-rw-r--r--libqpdf/QPDFObjectHandle.cc20
-rw-r--r--libqpdf/QPDFPageDocumentHelper.cc10
-rw-r--r--libqpdf/QPDFPageObjectHelper.cc43
-rw-r--r--libqpdf/QPDF_optimization.cc8
4 files changed, 46 insertions, 35 deletions
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index a0d45c86..b802a55c 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -18,6 +18,7 @@
#include <qpdf/Pl_QPDFTokenizer.hh>
#include <qpdf/BufferInputSource.hh>
#include <qpdf/QPDFExc.hh>
+#include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
@@ -1109,24 +1110,11 @@ QPDFObjectHandle::getGeneration() const
std::map<std::string, QPDFObjectHandle>
QPDFObjectHandle::getPageImages()
{
- // Note: this code doesn't handle inherited resources. If this
- // page dictionary doesn't have a /Resources key or has one whose
- // value is null or an empty dictionary, you are supposed to walk
- // up the page tree until you find a /Resources dictionary. As of
- // this writing, I don't have any test files that use inherited
- // resources, and hand-generating one won't be a good test because
- // any mistakes in my understanding would be present in both the
- // code and the test file.
-
- // NOTE: If support of inherited resources (see above comment) is
- // implemented, edit comment in QPDFObjectHandle.hh for this
- // function. Also remove call to pushInheritedAttributesToPage
- // from qpdf.cc when show_page_images is true.
-
std::map<std::string, QPDFObjectHandle> result;
- if (this->hasKey("/Resources"))
+ QPDFObjectHandle resources =
+ QPDFPageObjectHelper(*this).getAttribute("/Resources", false);
+ if (resources.isDictionary())
{
- QPDFObjectHandle resources = this->getKey("/Resources");
if (resources.hasKey("/XObject"))
{
QPDFObjectHandle xobject = resources.getKey("/XObject");
diff --git a/libqpdf/QPDFPageDocumentHelper.cc b/libqpdf/QPDFPageDocumentHelper.cc
index fa50c471..3eec789b 100644
--- a/libqpdf/QPDFPageDocumentHelper.cc
+++ b/libqpdf/QPDFPageDocumentHelper.cc
@@ -79,20 +79,12 @@ QPDFPageDocumentHelper::flattenAnnotations(
"document does not have updated appearance streams,"
" so form fields will not be flattened");
}
- pushInheritedAttributesToPage();
std::vector<QPDFPageObjectHelper> pages = getAllPages();
for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin();
iter != pages.end(); ++iter)
{
QPDFPageObjectHelper ph(*iter);
- QPDFObjectHandle page_oh = ph.getObjectHandle();
- if (page_oh.getKey("/Resources").isIndirect())
- {
- QTC::TC("qpdf", "QPDFPageDocumentHelper indirect resources");
- page_oh.replaceKey("/Resources",
- page_oh.getKey("/Resources").shallowCopy());
- }
- QPDFObjectHandle resources = ph.getObjectHandle().getKey("/Resources");
+ QPDFObjectHandle resources = ph.getAttribute("/Resources", true);
if (! resources.isDictionary())
{
// This should never happen and is not exercised in the
diff --git a/libqpdf/QPDFPageObjectHelper.cc b/libqpdf/QPDFPageObjectHelper.cc
index c5ede04f..4d58da32 100644
--- a/libqpdf/QPDFPageObjectHelper.cc
+++ b/libqpdf/QPDFPageObjectHelper.cc
@@ -15,6 +15,42 @@ QPDFPageObjectHelper::QPDFPageObjectHelper(QPDFObjectHandle oh) :
{
}
+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;
+ bool inherited = false;
+ while (inheritable && result.isNull() && node.hasKey("/Parent"))
+ {
+ 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");
+ result = result.shallowCopy();
+ this->oh.replaceKey(name, result);
+ }
+ return result;
+}
+
+
std::map<std::string, QPDFObjectHandle>
QPDFPageObjectHelper::getPageImages()
{
@@ -159,12 +195,7 @@ QPDFPageObjectHelper::removeUnreferencedResources()
std::vector<std::string> to_filter;
to_filter.push_back("/Font");
to_filter.push_back("/XObject");
- QPDFObjectHandle resources = this->oh.getKey("/Resources");
- if (resources.isDictionary())
- {
- resources = resources.shallowCopy();
- this->oh.replaceKey("/Resources", resources);
- }
+ QPDFObjectHandle resources = getAttribute("/Resources", true);
for (std::vector<std::string>::iterator d_iter = to_filter.begin();
d_iter != to_filter.end(); ++d_iter)
{
diff --git a/libqpdf/QPDF_optimization.cc b/libqpdf/QPDF_optimization.cc
index 59a01ea3..f282e5f3 100644
--- a/libqpdf/QPDF_optimization.cc
+++ b/libqpdf/QPDF_optimization.cc
@@ -208,10 +208,10 @@ QPDF::pushInheritedAttributesToPageInternal2(
if (type == "/Pages")
{
- // Make a list of inheritable keys. Any key other than /Type,
- // /Parent, Kids, or /Count is an inheritable attribute. Push
- // this object onto the stack of pages nodes that have values
- // for this attribute.
+ // Make a list of inheritable keys. Only the keys /MediaBox,
+ // /CropBox, /Resources, and /Rotate are inheritable
+ // attributes. Push this object onto the stack of pages nodes
+ // that have values for this attribute.
std::set<std::string> inheritable_keys;
std::set<std::string> keys = cur_pages.getKeys();