From 73752683c936af0f5a556982c2c59516d2914ee3 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Wed, 3 Nov 2021 10:12:50 -0400 Subject: [PATCH] Fix overlay/underlay on page with no resources (fixes #527) --- ChangeLog | 5 +++++ manual/qpdf-manual.xml | 6 ++++++ qpdf/qpdf.cc | 12 +++++++++++- qpdf/qpdf.testcov | 1 + qpdf/qtest/qpdf.test | 11 ++++++++++- qpdf/qtest/qpdf/overlay-no-resources.pdf | Bin 0 -> 1130 bytes qpdf/qtest/qpdf/page-with-no-resources.pdf | 21 +++++++++++++++++++++ 7 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 qpdf/qtest/qpdf/overlay-no-resources.pdf create mode 100644 qpdf/qtest/qpdf/page-with-no-resources.pdf diff --git a/ChangeLog b/ChangeLog index efb2173a..24bbc569 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2021-11-03 Jay Berkenbilt + + * Bug fix: make overlay/underlay work on a page with no resource + dictionary. Fixes #527. + 2021-11-02 Jay Berkenbilt * Add QPDF::findPage to the public API. This is primarily to help diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml index 8924dc51..7cd22459 100644 --- a/manual/qpdf-manual.xml +++ b/manual/qpdf-manual.xml @@ -5080,6 +5080,12 @@ print "\n"; that could occur when given bogus input. + + + Properly handle overlay/underlay on completely empty pages + (with no resource dictionary). + + diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index 2ed03cff..e1cd62da 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -5226,6 +5226,12 @@ static void do_under_overlay_for_page( std::string content; int min_suffix = 1; QPDFObjectHandle resources = dest_page.getAttribute("/Resources", true); + if (! resources.isDictionary()) + { + QTC::TC("qpdf", "qpdf overlay page with no resources"); + resources = QPDFObjectHandle::newDictionary(); + dest_page.getObjectHandle().replaceKey("/Resources", resources); + } for (std::vector::iterator iter = pagenos[pageno].begin(); iter != pagenos[pageno].end(); ++iter) { @@ -5257,7 +5263,11 @@ static void do_under_overlay_for_page( { resources.mergeResources( QPDFObjectHandle::parse("<< /XObject << >> >>")); - resources.getKey("/XObject").replaceKey(name, fo[from_pageno]); + auto xobject = resources.getKey("/XObject"); + if (xobject.isDictionary()) + { + xobject.replaceKey(name, fo[from_pageno]); + } ++min_suffix; content += new_content; } diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 0cb56525..68a32d43 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -596,3 +596,4 @@ QPDFWriter preserve object streams 1 QPDFWriter exclude from object stream 0 check unclosed --pages 1 QPDF_pages findPage not found 0 +qpdf overlay page with no resources 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 5c58c5a3..fc8c709f 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -477,7 +477,7 @@ $td->runtest("compare files", show_ntests(); # ---------- $td->notify("--- Form XObject, underlay, overlay ---"); -$n_tests += 20; +$n_tests += 22; $td->runtest("form xobject creation", {$td->COMMAND => "test_driver 55 fxo-red.pdf"}, @@ -550,6 +550,15 @@ $td->runtest("page operations on form xobject", {$td->FILE => "page-ops-on-form-xobject.out", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); +$td->runtest("overlay on page with no resources", + {$td->COMMAND => + "qpdf --deterministic-id page-with-no-resources.pdf" . + " --overlay minimal.pdf -- a.pdf"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check overlay with no resources output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "overlay-no-resources.pdf"}); show_ntests(); # ---------- diff --git a/qpdf/qtest/qpdf/overlay-no-resources.pdf b/qpdf/qtest/qpdf/overlay-no-resources.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4b41f745d6e44ced745b060b08033cdeac7a80b8 GIT binary patch literal 1130 zcmah|J#W)M7&b+ff+a@w7l|x<)V}jqB1IOosYS&{LlQous>9iSow`bFWM3g52L1pG z8&W4EBxe2qYpM#t1S^HkFfhP`xO3yABtuWKY(IC;`|;fKR$EQ)3RyDL>igfX|EdIZ zNd0ZK(EzQ*dYA(hNE@{7lZOb}3gfJw_P}*jOhS23ZkL3WbSL3JK)Vr#Ic$JYP&Z5R zQM@TtZcnKR$An9kS+J~jV-pHaoq~wmVws?oMYb_dcd|fKE$e@< z?r&qji*Ij8z%D|%uBiTaNynOzsmqFPV$$PVKy=W&xX&>Y?>^($#2^h(l5(CQ8>qwG zONR@J@*?M_12ZSR8$>jI_1OdtbVhy>Hpsg9T;()S1y-f3n6& ze=NtMe(gH;A0dwe2HI*Ot|U%+pxuv?Ye^nYf!k~#Y%3boCf!IUi~l1-7qO<6l+DXj z8^T#lPaMJ_ht1OK!we%;hq|gy7TA_$SP;PkBjVEKf@F%>!dNpHp~C(%7`5wjm|@Oi zrX|L7hHE?Xd7YY=&hi}3SlkybmKWbnQ#q%_V0YrD2zAibny}G`OeeC4Wl?5E6m_a2 zq0F{ybSQ?l8Muug@Iw}b0oE8{rtkZ<> +endobj +2 0 obj +<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >> +endobj +3 0 obj +<< /MediaBox [ 0.0 0.0 612 792 ] /Parent 2 0 R /Type /Page >> +endobj +xref +0 4 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +0000000123 00000 n +trailer << /Root 1 0 R /Size 4 /ID [<0c18b42478a35cdccff23c62f4c7b946>] >> +startxref +200 +%%EOF