2
1
mirror of https://github.com/qpdf/qpdf.git synced 2025-01-03 07:12:28 +00:00

QPDFPageObjectHelper::getPageImages: support form XObjects

This commit is contained in:
Jay Berkenbilt 2020-12-31 11:38:27 -05:00
parent 1562d34c09
commit e7a8554563
4 changed files with 73 additions and 60 deletions

View File

@ -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();

View File

@ -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>

View File

@ -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);

View File

@ -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