diff --git a/libqpdf/QPDFAcroFormDocumentHelper.cc b/libqpdf/QPDFAcroFormDocumentHelper.cc index c0d0207..390c33f 100644 --- a/libqpdf/QPDFAcroFormDocumentHelper.cc +++ b/libqpdf/QPDFAcroFormDocumentHelper.cc @@ -843,7 +843,14 @@ QPDFAcroFormDocumentHelper::transformAnnotations( from_afdh = &QPDFAcroFormDocumentHelper::get(*from_qpdf); } m->transformAnnotations( - a_old_annots, new_annots, new_fields, old_fields, cm, from_qpdf, from_afdh->m.get()); + a_old_annots, + new_annots, + new_fields, + old_fields, + cm, + from_qpdf, + from_afdh->m.get(), + nullptr); } void @@ -854,7 +861,8 @@ AcroForm::transformAnnotations( std::set& old_fields, QPDFMatrix const& cm, QPDF* from_qpdf, - AcroForm* from_afdh) + AcroForm* from_afdh, + QPDFObjectHandle* new_page) { qpdf_expect(from_qpdf); qpdf_expect(from_afdh); @@ -1149,6 +1157,9 @@ AcroForm::transformAnnotations( } auto rect = cm.transformRectangle(annot["/Rect"].getArrayAsRectangle()); annot.replaceKey("/Rect", QPDFObjectHandle::newFromRectangle(rect)); + if (new_page && annot.contains("/P")) { + annot.replace("/P", *new_page); + } } } @@ -1169,7 +1180,7 @@ AcroForm::fixCopiedAnnotations( AcroForm& from_afdh, std::set* added_fields) { - auto old_annots = from_page.getKey("/Annots"); + auto const& old_annots = from_page.getKey("/Annots"); if (old_annots.empty() || !old_annots.isArray()) { return; } @@ -1184,7 +1195,8 @@ AcroForm::fixCopiedAnnotations( old_fields, QPDFMatrix(), &(from_afdh.qpdf), - &from_afdh); + &from_afdh, + &to_page); to_page.replaceKey("/Annots", QPDFObjectHandle::newArray(new_annots)); addAndRenameFormFields(new_fields); diff --git a/libqpdf/qpdf/AcroForm.hh b/libqpdf/qpdf/AcroForm.hh index 4c01269..e15cfb0 100644 --- a/libqpdf/qpdf/AcroForm.hh +++ b/libqpdf/qpdf/AcroForm.hh @@ -166,7 +166,8 @@ namespace qpdf::impl std::set& old_fields, QPDFMatrix const& cm, QPDF* from_qpdf, - AcroForm* from_afdh); + AcroForm* from_afdh, + QPDFObjectHandle* new_page); // Copy form fields and annotations from one page to another, allowing the from page to be // in a different QPDF or in the same QPDF. This would typically be called after calling diff --git a/libqpdf/qpdf/QPDFObjectHandle_private.hh b/libqpdf/qpdf/QPDFObjectHandle_private.hh index cc30057..ab54009 100644 --- a/libqpdf/qpdf/QPDFObjectHandle_private.hh +++ b/libqpdf/qpdf/QPDFObjectHandle_private.hh @@ -324,6 +324,12 @@ namespace qpdf { } + explicit + operator bool() const + { + return obj != nullptr; + } + // Return the integer value. If the object is not a valid Integer, throw a // std::invalid_argument exception. If the object is out of range for the target type, // throw a std::overflow_error or std::underflow_error exception. diff --git a/manual/release-notes.rst b/manual/release-notes.rst index 0b134cb..d9f53a3 100644 --- a/manual/release-notes.rst +++ b/manual/release-notes.rst @@ -43,6 +43,9 @@ more detail. - When parsing qpdf JSON input files allow empty name objects. These are allowed by the PDF specification but were previously rejected. + - ``QPDFAcroFormDocumentHelper::fixCopiedAnnotations`` now correctly + updates any annotation's ``/P`` entries to point to the owning page. + - Library Enhancements - Add ``QPDFNameTreeObjectHelper`` and ``QPDFNumberTreeObjectHelper`` diff --git a/qpdf/qtest/copy-annotations.test b/qpdf/qtest/copy-annotations.test index a730135..2215764 100644 --- a/qpdf/qtest/copy-annotations.test +++ b/qpdf/qtest/copy-annotations.test @@ -71,8 +71,7 @@ $td->runtest("copy annotations with /P entry", $td->runtest("check output", {$td->FILE => "a.pdf"}, - {$td->FILE => "annotations-no-acroform-with-p.out.pdf"}, - $td->EXPECT_FAILURE); + {$td->FILE => "annotations-no-acroform-with-p.out.pdf"}); $td->runtest("copy annotations no acroform from foreign file", {$td->COMMAND => @@ -167,7 +166,7 @@ $td->runtest("check output", # field-resource-conflict.pdf was crafted so that an appearance stream # had an existing resource that it actually referenced in the # appearance stream whose name, /F1_1, clashed with the result of -# resolving conflicts in /DR. It's a crazy corner case, but it if it +# resolving conflicts in /DR. It's a crazy corner case, but if it # ever happened, it would be really hard to track down, and it could # arise through multiple passes through qpdf with intervening edits. $td->runtest("appearance stream resource conflict", diff --git a/qpdf/qtest/qpdf/resolved-appearance-conflicts.pdf b/qpdf/qtest/qpdf/resolved-appearance-conflicts.pdf index ab903e4..09ce376 100644 --- a/qpdf/qtest/qpdf/resolved-appearance-conflicts.pdf +++ b/qpdf/qtest/qpdf/resolved-appearance-conflicts.pdf @@ -119,7 +119,7 @@ endobj /MK << /CA (8) >> - /P 17 0 R + /P 26 0 R /Rect [ 174.5 719.7 @@ -136,7 +136,7 @@ endobj 6 0 obj << /AP << - /N 26 0 R + /N 27 0 R >> /DA (0.29803 0.29803 0.29803 rg /F1 12 Tf) /DR << @@ -145,7 +145,7 @@ endobj /DV /F 4 /FT /Tx - /P 17 0 R + /P 26 0 R /Rect [ 59.6 715 @@ -163,8 +163,8 @@ endobj << /AP << /N << - /Off 28 0 R - /Yes 30 0 R + /Off 29 0 R + /Yes 31 0 R >> >> /AS /Off @@ -176,7 +176,7 @@ endobj /MK << /CA (8) >> - /P 32 0 R + /P 33 0 R /Rect [ 174.5 719.7 @@ -193,14 +193,14 @@ endobj 8 0 obj << /AP << - /N 33 0 R + /N 34 0 R >> /DA (0.29803 0.29803 0.29803 rg /F1_1 12 Tf) /DR 2 0 R /DV /F 4 /FT /Tx - /P 32 0 R + /P 33 0 R /Rect [ 59.6 715 @@ -219,8 +219,8 @@ endobj /Count 3 /Kids [ 17 0 R - 35 0 R - 32 0 R + 26 0 R + 33 0 R ] /Type /Pages >> @@ -431,8 +431,41 @@ endobj 81 endobj +%% Page 2 26 0 obj << + /Annots [ + 5 0 R + 6 0 R + ] + /Contents 37 0 R + /Group << + /CS /DeviceRGB + /I true + /S /Transparency + >> + /MediaBox [ + 0 + 0 + 611.971653543307 + 791.971653543307 + ] + /Parent 9 0 R + /Resources << + /Font << + /F1 10 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +27 0 obj +<< /BBox [ 0 0 @@ -447,7 +480,7 @@ endobj >> /Subtype /Form /Type /XObject - /Length 27 0 R + /Length 28 0 R >> stream BT /F1_1 12 Tf ET @@ -456,11 +489,11 @@ EMC endstream endobj -27 0 obj +28 0 obj 30 endobj -28 0 obj +29 0 obj << /BBox [ 0 @@ -471,7 +504,7 @@ endobj /Resources 39 0 R /Subtype /Form /Type /XObject - /Length 29 0 R + /Length 30 0 R >> stream /Tx BMC @@ -479,11 +512,11 @@ EMC endstream endobj -29 0 obj +30 0 obj 12 endobj -30 0 obj +31 0 obj << /BBox [ 0 @@ -494,7 +527,7 @@ endobj /Resources 40 0 R /Subtype /Form /Type /XObject - /Length 31 0 R + /Length 32 0 R >> stream /Tx BMC @@ -507,12 +540,12 @@ EMC endstream endobj -31 0 obj +32 0 obj 83 endobj %% Page 3 -32 0 obj +33 0 obj << /Annots [ 7 0 R @@ -544,7 +577,7 @@ endobj >> endobj -33 0 obj +34 0 obj << /BBox [ 0 @@ -560,7 +593,7 @@ endobj >> /Subtype /Form /Type /XObject - /Length 34 0 R + /Length 35 0 R >> stream BT /F1_1_1 12 Tf ET @@ -569,41 +602,8 @@ EMC endstream endobj -34 0 obj -32 -endobj - -%% Page 2 35 0 obj -<< - /Annots [ - 5 0 R - 6 0 R - ] - /Contents 37 0 R - /Group << - /CS /DeviceRGB - /I true - /S /Transparency - >> - /MediaBox [ - 0 - 0 - 611.971653543307 - 791.971653543307 - ] - /Parent 9 0 R - /Resources << - /Font << - /F1 10 0 R - >> - /ProcSet [ - /PDF - /Text - ] - >> - /Type /Page ->> +32 endobj 36 0 obj @@ -742,16 +742,16 @@ xref 0000004092 00000 n 0000004112 00000 n 0000004347 00000 n -0000004367 00000 n -0000004610 00000 n -0000004630 00000 n -0000004797 00000 n -0000004817 00000 n -0000005055 00000 n -0000005085 00000 n -0000005436 00000 n -0000005685 00000 n -0000005715 00000 n +0000004377 00000 n +0000004728 00000 n +0000004971 00000 n +0000004991 00000 n +0000005158 00000 n +0000005178 00000 n +0000005416 00000 n +0000005446 00000 n +0000005797 00000 n +0000006046 00000 n 0000006066 00000 n 0000006194 00000 n 0000006531 00000 n