mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
Add methods for copying form fields
This commit is contained in:
parent
f02aa74bf5
commit
1f35ec9988
@ -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.
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user