mirror of
https://github.com/qpdf/qpdf.git
synced 2025-01-02 22:50:20 +00:00
Preserve form fields when splitting pages (fixes #340)
This commit is contained in:
parent
1f35ec9988
commit
83216e640c
@ -1,5 +1,8 @@
|
||||
2021-02-22 Jay Berkenbilt <ejb@ql.org>
|
||||
|
||||
* From qpdf CLI, --pages and --split-pages will properly preserve
|
||||
interactive form functionality. Fixes #340.
|
||||
|
||||
* Add QPDFAcroFormDocumentHelper::copyFieldsFromForeignPage to
|
||||
copy form fields from a foreign page into the current file.
|
||||
|
||||
|
@ -676,10 +676,16 @@ QPDFAcroFormDocumentHelper::copyFieldsFromForeignPage(
|
||||
QPDFPageObjectHelper foreign_page,
|
||||
QPDFAcroFormDocumentHelper& foreign_afdh)
|
||||
{
|
||||
std::set<QPDFObjGen> added;
|
||||
for (auto field: foreign_afdh.getFormFieldsForPage(foreign_page))
|
||||
{
|
||||
auto new_field = this->qpdf.copyForeignObject(
|
||||
field.getObjectHandle());
|
||||
auto og = new_field.getObjGen();
|
||||
if (! added.count(og))
|
||||
{
|
||||
addFormField(new_field);
|
||||
added.insert(og);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
41
qpdf/qpdf.cc
41
qpdf/qpdf.cc
@ -5143,6 +5143,19 @@ static void get_uo_pagenos(UnderOverlay& uo,
|
||||
}
|
||||
}
|
||||
|
||||
static QPDFAcroFormDocumentHelper* get_afdh_for_qpdf(
|
||||
std::map<unsigned long long,
|
||||
PointerHolder<QPDFAcroFormDocumentHelper>>& afdh_map,
|
||||
QPDF* q)
|
||||
{
|
||||
auto uid = q->getUniqueId();
|
||||
if (! afdh_map.count(uid))
|
||||
{
|
||||
afdh_map[uid] = new QPDFAcroFormDocumentHelper(*q);
|
||||
}
|
||||
return afdh_map[uid].getPointer();
|
||||
}
|
||||
|
||||
static void do_under_overlay_for_page(
|
||||
QPDF& pdf,
|
||||
Options& o,
|
||||
@ -5164,12 +5177,7 @@ static void do_under_overlay_for_page(
|
||||
PointerHolder<QPDFAcroFormDocumentHelper>> afdh;
|
||||
auto make_afdh = [&](QPDFPageObjectHelper& ph) {
|
||||
QPDF* q = ph.getObjectHandle().getOwningQPDF();
|
||||
auto uid = q->getUniqueId();
|
||||
if (! afdh.count(uid))
|
||||
{
|
||||
afdh[uid] = new QPDFAcroFormDocumentHelper(*q);
|
||||
}
|
||||
return afdh[uid].getPointer();
|
||||
return get_afdh_for_qpdf(afdh, q);
|
||||
};
|
||||
auto dest_afdh = make_afdh(dest_page);
|
||||
|
||||
@ -5835,6 +5843,9 @@ static void handle_page_specs(QPDF& pdf, Options& o, bool& warnings)
|
||||
std::vector<QPDFObjectHandle> new_labels;
|
||||
bool any_page_labels = false;
|
||||
int out_pageno = 0;
|
||||
std::map<unsigned long long,
|
||||
PointerHolder<QPDFAcroFormDocumentHelper>> afdh_map;
|
||||
auto this_afdh = get_afdh_for_qpdf(afdh_map, &pdf);
|
||||
for (std::vector<QPDFPageData>::iterator iter =
|
||||
parsed_specs.begin();
|
||||
iter != parsed_specs.end(); ++iter)
|
||||
@ -5847,6 +5858,7 @@ static void handle_page_specs(QPDF& pdf, Options& o, bool& warnings)
|
||||
cis->stayOpen(true);
|
||||
}
|
||||
QPDFPageLabelDocumentHelper pldh(*page_data.qpdf);
|
||||
auto other_afdh = get_afdh_for_qpdf(afdh_map, page_data.qpdf);
|
||||
if (pldh.hasPageLabels())
|
||||
{
|
||||
any_page_labels = true;
|
||||
@ -5891,6 +5903,11 @@ static void handle_page_specs(QPDF& pdf, Options& o, bool& warnings)
|
||||
// of the fact that we are using it.
|
||||
selected_from_orig.insert(pageno);
|
||||
}
|
||||
else if (other_afdh->hasAcroForm())
|
||||
{
|
||||
QTC::TC("qpdf", "qpdf copy form fields in pages");
|
||||
this_afdh->copyFieldsFromForeignPage(to_copy, *other_afdh);
|
||||
}
|
||||
}
|
||||
if (page_data.qpdf->anyWarnings())
|
||||
{
|
||||
@ -6269,6 +6286,7 @@ static void do_split_pages(QPDF& pdf, Options& o, bool& warnings)
|
||||
dh.removeUnreferencedResources();
|
||||
}
|
||||
QPDFPageLabelDocumentHelper pldh(pdf);
|
||||
QPDFAcroFormDocumentHelper afdh(pdf);
|
||||
std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
|
||||
size_t pageno_len = QUtil::uint_to_string(pages.size()).length();
|
||||
size_t num_pages = pages.size();
|
||||
@ -6282,6 +6300,11 @@ static void do_split_pages(QPDF& pdf, Options& o, bool& warnings)
|
||||
}
|
||||
QPDF outpdf;
|
||||
outpdf.emptyPDF();
|
||||
PointerHolder<QPDFAcroFormDocumentHelper> out_afdh;
|
||||
if (afdh.hasAcroForm())
|
||||
{
|
||||
out_afdh = new QPDFAcroFormDocumentHelper(outpdf);
|
||||
}
|
||||
if (o.suppress_warnings)
|
||||
{
|
||||
outpdf.setSuppressWarnings(true);
|
||||
@ -6290,6 +6313,12 @@ static void do_split_pages(QPDF& pdf, Options& o, bool& warnings)
|
||||
{
|
||||
QPDFObjectHandle page = pages.at(pageno - 1);
|
||||
outpdf.addPage(page, false);
|
||||
if (out_afdh.getPointer())
|
||||
{
|
||||
QTC::TC("qpdf", "qpdf copy form fields in split_pages");
|
||||
out_afdh->copyFieldsFromForeignPage(
|
||||
QPDFPageObjectHelper(page), afdh);
|
||||
}
|
||||
}
|
||||
if (pldh.hasPageLabels())
|
||||
{
|
||||
|
@ -575,3 +575,5 @@ QPDFPageObjectHelper flatten inherit rotate 0
|
||||
QPDFAcroFormDocumentHelper copy annotation 3
|
||||
QPDFAcroFormDocumentHelper field with parent 3
|
||||
QPDFAcroFormDocumentHelper modify ap matrix 0
|
||||
qpdf copy form fields in split_pages 0
|
||||
qpdf copy form fields in pages 0
|
||||
|
@ -2414,7 +2414,7 @@ foreach my $f (qw(screen print))
|
||||
show_ntests();
|
||||
# ----------
|
||||
$td->notify("--- Copy Annotations ---");
|
||||
$n_tests += 16;
|
||||
$n_tests += 21;
|
||||
|
||||
$td->runtest("complex copy annotations",
|
||||
{$td->COMMAND =>
|
||||
@ -2458,6 +2458,28 @@ foreach my $d ([1, "appearances-1.pdf"],
|
||||
{$td->FILE => "test80b$n.pdf"});
|
||||
}
|
||||
|
||||
$td->runtest("page extraction with fields",
|
||||
{$td->COMMAND =>
|
||||
"qpdf --static-id --empty" .
|
||||
" --pages fields-two-pages.pdf -- a.pdf"},
|
||||
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("check output",
|
||||
{$td->FILE => "a.pdf"},
|
||||
{$td->FILE => "fields-pages-out.pdf"});
|
||||
$td->runtest("page splitting with fields",
|
||||
{$td->COMMAND =>
|
||||
"qpdf --static-id" .
|
||||
" --split-pages fields-two-pages.pdf a.pdf"},
|
||||
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
for (my $i = 1; $i <= 2; ++$i)
|
||||
{
|
||||
$td->runtest("check output",
|
||||
{$td->FILE => "a-$i.pdf"},
|
||||
{$td->FILE => "fields-split-$i.pdf"});
|
||||
}
|
||||
|
||||
show_ntests();
|
||||
# ----------
|
||||
$td->notify("--- Page Tree Issues ---");
|
||||
|
BIN
qpdf/qtest/qpdf/fields-pages-out.pdf
Normal file
BIN
qpdf/qtest/qpdf/fields-pages-out.pdf
Normal file
Binary file not shown.
BIN
qpdf/qtest/qpdf/fields-split-1.pdf
Normal file
BIN
qpdf/qtest/qpdf/fields-split-1.pdf
Normal file
Binary file not shown.
BIN
qpdf/qtest/qpdf/fields-split-2.pdf
Normal file
BIN
qpdf/qtest/qpdf/fields-split-2.pdf
Normal file
Binary file not shown.
BIN
qpdf/qtest/qpdf/fields-two-pages.pdf
Normal file
BIN
qpdf/qtest/qpdf/fields-two-pages.pdf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user