Commit e7a85545639d6d09923abb8fb300dda5889b110b

Authored by Jay Berkenbilt
1 parent 1562d34c

QPDFPageObjectHelper::getPageImages: support form XObjects

include/qpdf/QPDFPageObjectHelper.hh
@@ -32,6 +32,10 @@ @@ -32,6 +32,10 @@
32 32
33 class QPDFPageObjectHelper: public QPDFObjectHelper 33 class QPDFPageObjectHelper: public QPDFObjectHelper
34 { 34 {
  35 + // This is a helper class for page objects, but as of qpdf 10.1,
  36 + // many of the methods also work for form XObjects. When this is
  37 + // the case, it is noted in the comment.
  38 +
35 public: 39 public:
36 QPDF_DLL 40 QPDF_DLL
37 QPDFPageObjectHelper(QPDFObjectHandle); 41 QPDFPageObjectHelper(QPDFObjectHandle);
@@ -40,14 +44,15 @@ class QPDFPageObjectHelper: public QPDFObjectHelper @@ -40,14 +44,15 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
40 { 44 {
41 } 45 }
42 46
43 - // Return the effective value of this attribute for the page. If  
44 - // the requested attribute is not present on the page but is 47 + // Works with pages and form XObjects. Return the effective value
  48 + // of this attribute for the page/form XObject. For pages, if the
  49 + // requested attribute is not present on the page but is
45 // inheritable, look up through the page's ancestors in the page 50 // inheritable, look up through the page's ancestors in the page
46 // tree. If copy_if_shared is true, then this method will replace 51 // tree. If copy_if_shared is true, then this method will replace
47 // the attribute with a shallow copy if it is in indirect or 52 // the attribute with a shallow copy if it is in indirect or
48 // inherited and return the copy. You should do this if you are 53 // inherited and return the copy. You should do this if you are
49 // going to modify the returned object and want the modifications 54 // going to modify the returned object and want the modifications
50 - // to apply to the current page only. 55 + // to apply to the current page/form XObject only.
51 QPDF_DLL 56 QPDF_DLL
52 QPDFObjectHandle 57 QPDFObjectHandle
53 getAttribute(std::string const& name, bool copy_if_shared); 58 getAttribute(std::string const& name, bool copy_if_shared);
@@ -70,7 +75,8 @@ class QPDFPageObjectHelper: public QPDFObjectHelper @@ -70,7 +75,8 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
70 // Returns an empty map if there are no images or no resources. 75 // Returns an empty map if there are no images or no resources.
71 // Prior to qpdf 8.4.0, this function did not support inherited 76 // Prior to qpdf 8.4.0, this function did not support inherited
72 // resources, but it does now. Return value is a map from XObject 77 // resources, but it does now. Return value is a map from XObject
73 - // name to the image object, which is always a stream. 78 + // name to the image object, which is always a stream. Works with
  79 + // form XObjects as well as pages.
74 QPDF_DLL 80 QPDF_DLL
75 std::map<std::string, QPDFObjectHandle> getPageImages(); 81 std::map<std::string, QPDFObjectHandle> getPageImages();
76 82
libqpdf/QPDFObjectHandle.cc
@@ -1320,35 +1320,7 @@ QPDFObjectHandle::getGeneration() const @@ -1320,35 +1320,7 @@ QPDFObjectHandle::getGeneration() const
1320 std::map<std::string, QPDFObjectHandle> 1320 std::map<std::string, QPDFObjectHandle>
1321 QPDFObjectHandle::getPageImages() 1321 QPDFObjectHandle::getPageImages()
1322 { 1322 {
1323 - std::map<std::string, QPDFObjectHandle> result;  
1324 - QPDFObjectHandle resources =  
1325 - QPDFPageObjectHelper(*this).getAttribute("/Resources", false);  
1326 - if (resources.isDictionary())  
1327 - {  
1328 - if (resources.hasKey("/XObject"))  
1329 - {  
1330 - QPDFObjectHandle xobject = resources.getKey("/XObject");  
1331 - std::set<std::string> keys = xobject.getKeys();  
1332 - for (std::set<std::string>::iterator iter = keys.begin();  
1333 - iter != keys.end(); ++iter)  
1334 - {  
1335 - std::string key = (*iter);  
1336 - QPDFObjectHandle value = xobject.getKey(key);  
1337 - if (value.isStream())  
1338 - {  
1339 - QPDFObjectHandle dict = value.getDict();  
1340 - if (dict.hasKey("/Subtype") &&  
1341 - (dict.getKey("/Subtype").getName() == "/Image") &&  
1342 - (! dict.hasKey("/ImageMask")))  
1343 - {  
1344 - result[key] = value;  
1345 - }  
1346 - }  
1347 - }  
1348 - }  
1349 - }  
1350 -  
1351 - return result; 1323 + return QPDFPageObjectHelper(*this).getPageImages();
1352 } 1324 }
1353 1325
1354 std::vector<QPDFObjectHandle> 1326 std::vector<QPDFObjectHandle>
libqpdf/QPDFPageObjectHelper.cc
@@ -314,33 +314,46 @@ QPDFObjectHandle @@ -314,33 +314,46 @@ QPDFObjectHandle
314 QPDFPageObjectHelper::getAttribute(std::string const& name, 314 QPDFPageObjectHelper::getAttribute(std::string const& name,
315 bool copy_if_shared) 315 bool copy_if_shared)
316 { 316 {
317 - bool inheritable = ((name == "/MediaBox") || (name == "/CropBox") ||  
318 - (name == "/Resources") || (name == "/Rotate"));  
319 -  
320 - QPDFObjectHandle node = this->oh;  
321 - QPDFObjectHandle result(node.getKey(name));  
322 - std::set<QPDFObjGen> seen; 317 + QPDFObjectHandle result;
  318 + QPDFObjectHandle dict;
  319 + bool is_form_xobject = this->oh.isFormXObject();
323 bool inherited = false; 320 bool inherited = false;
324 - while (inheritable && result.isNull() && node.hasKey("/Parent")) 321 + if (is_form_xobject)
325 { 322 {
326 - seen.insert(node.getObjGen());  
327 - node = node.getKey("/Parent");  
328 - if (seen.count(node.getObjGen()))  
329 - {  
330 - break;  
331 - } 323 + dict = this->oh.getDict();
  324 + result = dict.getKey(name);
  325 + }
  326 + else
  327 + {
  328 + dict = this->oh;
  329 + bool inheritable = ((name == "/MediaBox") || (name == "/CropBox") ||
  330 + (name == "/Resources") || (name == "/Rotate"));
  331 +
  332 + QPDFObjectHandle node = dict;
332 result = node.getKey(name); 333 result = node.getKey(name);
333 - if (! result.isNull()) 334 + std::set<QPDFObjGen> seen;
  335 + while (inheritable && result.isNull() && node.hasKey("/Parent"))
334 { 336 {
335 - QTC::TC("qpdf", "QPDFPageObjectHelper non-trivial inheritance");  
336 - inherited = true; 337 + seen.insert(node.getObjGen());
  338 + node = node.getKey("/Parent");
  339 + if (seen.count(node.getObjGen()))
  340 + {
  341 + break;
  342 + }
  343 + result = node.getKey(name);
  344 + if (! result.isNull())
  345 + {
  346 + QTC::TC("qpdf", "QPDFPageObjectHelper non-trivial inheritance");
  347 + inherited = true;
  348 + }
337 } 349 }
338 } 350 }
339 if (copy_if_shared && (inherited || result.isIndirect())) 351 if (copy_if_shared && (inherited || result.isIndirect()))
340 { 352 {
341 - QTC::TC("qpdf", "QPDFPageObjectHelper copy shared attribute"); 353 + QTC::TC("qpdf", "QPDFPageObjectHelper copy shared attribute",
  354 + is_form_xobject ? 0 : 1);
342 result = result.shallowCopy(); 355 result = result.shallowCopy();
343 - this->oh.replaceKey(name, result); 356 + dict.replaceKey(name, result);
344 } 357 }
345 return result; 358 return result;
346 } 359 }
@@ -376,7 +389,34 @@ QPDFPageObjectHelper::getMediaBox(bool copy_if_shared) @@ -376,7 +389,34 @@ QPDFPageObjectHelper::getMediaBox(bool copy_if_shared)
376 std::map<std::string, QPDFObjectHandle> 389 std::map<std::string, QPDFObjectHandle>
377 QPDFPageObjectHelper::getPageImages() 390 QPDFPageObjectHelper::getPageImages()
378 { 391 {
379 - return this->oh.getPageImages(); 392 + std::map<std::string, QPDFObjectHandle> result;
  393 + QPDFObjectHandle resources = getAttribute("/Resources", false);
  394 + if (resources.isDictionary())
  395 + {
  396 + if (resources.hasKey("/XObject"))
  397 + {
  398 + QPDFObjectHandle xobject = resources.getKey("/XObject");
  399 + std::set<std::string> keys = xobject.getKeys();
  400 + for (std::set<std::string>::iterator iter = keys.begin();
  401 + iter != keys.end(); ++iter)
  402 + {
  403 + std::string key = (*iter);
  404 + QPDFObjectHandle value = xobject.getKey(key);
  405 + if (value.isStream())
  406 + {
  407 + QPDFObjectHandle dict = value.getDict();
  408 + if (dict.hasKey("/Subtype") &&
  409 + (dict.getKey("/Subtype").getName() == "/Image") &&
  410 + (! dict.hasKey("/ImageMask")))
  411 + {
  412 + result[key] = value;
  413 + }
  414 + }
  415 + }
  416 + }
  417 + }
  418 +
  419 + return result;
380 } 420 }
381 421
382 void 422 void
@@ -571,13 +611,8 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper( @@ -571,13 +611,8 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper(
571 removeUnreferencedResourcesHelper( 611 removeUnreferencedResourcesHelper(
572 resource.getDict(), seen, 612 resource.getDict(), seen,
573 [&resource]() { 613 [&resource]() {
574 - auto result = resource.getDict().getKey("/Resources");  
575 - if (result.isDictionary())  
576 - {  
577 - result = result.shallowCopy();  
578 - resource.getDict().replaceKey("/Resources", result);  
579 - }  
580 - return result; 614 + return QPDFPageObjectHelper(resource)
  615 + .getAttribute("/Resources", true);
581 }, 616 },
582 [&resource](QPDFObjectHandle::TokenFilter* f) { 617 [&resource](QPDFObjectHandle::TokenFilter* f) {
583 resource.filterAsContents(f); 618 resource.filterAsContents(f);
qpdf/qpdf.testcov
@@ -422,7 +422,7 @@ QPDFFormFieldObjectHelper create AP from scratch 0 @@ -422,7 +422,7 @@ QPDFFormFieldObjectHelper create AP from scratch 0
422 QPDFFormFieldObjectHelper replaced BMC at EOF 0 422 QPDFFormFieldObjectHelper replaced BMC at EOF 0
423 QPDFFormFieldObjectHelper fallback Tf 0 423 QPDFFormFieldObjectHelper fallback Tf 0
424 QPDFPageObjectHelper non-trivial inheritance 0 424 QPDFPageObjectHelper non-trivial inheritance 0
425 -QPDFPageObjectHelper copy shared attribute 0 425 +QPDFPageObjectHelper copy shared attribute 1
426 qpdf from_nr from repeat_nr 0 426 qpdf from_nr from repeat_nr 0
427 QPDF resolve duplicated page object 0 427 QPDF resolve duplicated page object 0
428 QPDF handle direct page object 0 428 QPDF handle direct page object 0