aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2021-02-22 23:44:13 +0100
committerJay Berkenbilt <ejb@ql.org>2021-02-23 00:42:06 +0100
commit1f35ec9988eaf1ad3705655c434701d175c5b49f (patch)
tree0b60da6e5f35a5ee00d98f272f9ec1d59ef85694
parentf02aa74bf5387c30e4ff6082beeb4b0d078b6294 (diff)
downloadqpdf-1f35ec9988eaf1ad3705655c434701d175c5b49f.tar.zst
Add methods for copying form fields
-rw-r--r--ChangeLog6
-rw-r--r--include/qpdf/QPDFAcroFormDocumentHelper.hh12
-rw-r--r--include/qpdf/QPDFFormFieldObjectHelper.hh7
-rw-r--r--libqpdf/QPDFAcroFormDocumentHelper.cc47
-rw-r--r--libqpdf/QPDFFormFieldObjectHelper.cc23
5 files changed, 81 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 43c716d6..8693e5d4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2021-02-22 Jay Berkenbilt <ejb@ql.org>
+ * Add QPDFAcroFormDocumentHelper::copyFieldsFromForeignPage to
+ copy form fields from a foreign page into the current file.
+
+ * Add QPDFFormFieldObjectHelper::getTopLevelField to get the
+ top-level field for a given form field.
+
* Update pdf-overlay-page example to include copying of
annotations.
diff --git a/include/qpdf/QPDFAcroFormDocumentHelper.hh b/include/qpdf/QPDFAcroFormDocumentHelper.hh
index eb9da5ad..fd28a579 100644
--- a/include/qpdf/QPDFAcroFormDocumentHelper.hh
+++ b/include/qpdf/QPDFAcroFormDocumentHelper.hh
@@ -140,6 +140,11 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
std::vector<QPDFAnnotationObjectHelper>
getWidgetAnnotationsForPage(QPDFPageObjectHelper);
+ // Return form fields for a page.
+ QPDF_DLL
+ std::vector<QPDFFormFieldObjectHelper>
+ getFormFieldsForPage(QPDFPageObjectHelper);
+
// Return the terminal field that is associated with this
// annotation. If the annotation dictionary is merged with the
// field dictionary, the underlying object will be the same, but
@@ -204,6 +209,13 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
QPDF* from_qpdf = nullptr,
QPDFAcroFormDocumentHelper* from_afdh = nullptr);
+ // Copy form fields from a page in a different QPDF object to this
+ // QPDF.
+ QPDF_DLL
+ void copyFieldsFromForeignPage(
+ QPDFPageObjectHelper foreign_page,
+ QPDFAcroFormDocumentHelper& foreign_afdh);
+
private:
void analyze();
void traverseField(QPDFObjectHandle field,
diff --git a/include/qpdf/QPDFFormFieldObjectHelper.hh b/include/qpdf/QPDFFormFieldObjectHelper.hh
index b9168d22..edb93df8 100644
--- a/include/qpdf/QPDFFormFieldObjectHelper.hh
+++ b/include/qpdf/QPDFFormFieldObjectHelper.hh
@@ -54,6 +54,13 @@ class QPDFFormFieldObjectHelper: public QPDFObjectHelper
QPDF_DLL
QPDFFormFieldObjectHelper getParent();
+ // Return the top-level field for this field. Typically this will
+ // be the field itself or its parent. If is_different is provided,
+ // it is set to true if the top-level field is different from the
+ // field itself; otherwise it is set to false.
+ QPDF_DLL
+ QPDFFormFieldObjectHelper getTopLevelField(bool* is_different = nullptr);
+
// Get a field value, possibly inheriting the value from an
// ancestor node.
QPDF_DLL
diff --git a/libqpdf/QPDFAcroFormDocumentHelper.cc b/libqpdf/QPDFAcroFormDocumentHelper.cc
index 84ddd432..dce413bd 100644
--- a/libqpdf/QPDFAcroFormDocumentHelper.cc
+++ b/libqpdf/QPDFAcroFormDocumentHelper.cc
@@ -132,6 +132,23 @@ QPDFAcroFormDocumentHelper::getWidgetAnnotationsForPage(QPDFPageObjectHelper h)
return h.getAnnotations("/Widget");
}
+std::vector<QPDFFormFieldObjectHelper>
+QPDFAcroFormDocumentHelper::getFormFieldsForPage(QPDFPageObjectHelper ph)
+{
+ std::vector<QPDFFormFieldObjectHelper> result;
+ auto widget_annotations = getWidgetAnnotationsForPage(ph);
+ for (auto annot: widget_annotations)
+ {
+ auto field = getFieldForAnnotation(annot);
+ field = field.getTopLevelField();
+ if (field.getObjectHandle().isDictionary())
+ {
+ result.push_back(field);
+ }
+ }
+ return result;
+}
+
QPDFFormFieldObjectHelper
QPDFAcroFormDocumentHelper::getFieldForAnnotation(QPDFAnnotationObjectHelper h)
{
@@ -501,19 +518,8 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
// annotation and field separately in this case.
have_field = true;
// Find the top-level field. It may be the field itself.
- top_field = ffield_oh;
- std::set<QPDFObjGen> seen;
- while (! top_field.getKey("/Parent").isNull())
- {
- top_field = top_field.getKey("/Parent");
- have_parent = true;
- auto og = top_field.getObjGen();
- if (seen.count(og))
- {
- break;
- }
- seen.insert(og);
- }
+ top_field = ffield.getTopLevelField(
+ &have_parent).getObjectHandle();
if (foreign)
{
// copyForeignObject returns the same value if called
@@ -537,7 +543,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
{
queue.push_back(top_field);
}
- seen.clear();
+ std::set<QPDFObjGen> seen;
while (! queue.empty())
{
QPDFObjectHandle obj = queue.front();
@@ -664,3 +670,16 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
"/Rect", QPDFObjectHandle::newFromRectangle(rect));
}
}
+
+void
+QPDFAcroFormDocumentHelper::copyFieldsFromForeignPage(
+ QPDFPageObjectHelper foreign_page,
+ QPDFAcroFormDocumentHelper& foreign_afdh)
+{
+ for (auto field: foreign_afdh.getFormFieldsForPage(foreign_page))
+ {
+ auto new_field = this->qpdf.copyForeignObject(
+ field.getObjectHandle());
+ addFormField(new_field);
+ }
+}
diff --git a/libqpdf/QPDFFormFieldObjectHelper.cc b/libqpdf/QPDFFormFieldObjectHelper.cc
index 97257c85..6933cb54 100644
--- a/libqpdf/QPDFFormFieldObjectHelper.cc
+++ b/libqpdf/QPDFFormFieldObjectHelper.cc
@@ -39,6 +39,29 @@ QPDFFormFieldObjectHelper::getParent()
return this->oh.getKey("/Parent"); // may be null
}
+QPDFFormFieldObjectHelper
+QPDFFormFieldObjectHelper::getTopLevelField(bool* is_different)
+{
+ auto top_field = this->oh;
+ std::set<QPDFObjGen> seen;
+ while (top_field.isDictionary() &&
+ (! top_field.getKey("/Parent").isNull()))
+ {
+ top_field = top_field.getKey("/Parent");
+ if (is_different)
+ {
+ *is_different = true;
+ }
+ auto og = top_field.getObjGen();
+ if (seen.count(og))
+ {
+ break;
+ }
+ seen.insert(og);
+ }
+ return QPDFFormFieldObjectHelper(top_field);
+}
+
QPDFObjectHandle
QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name)
{