aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2018-06-19 15:26:41 +0200
committerJay Berkenbilt <ejb@ql.org>2018-06-21 21:57:13 +0200
commit0b05111db80469d3f556209bfd856af1fda9b142 (patch)
tree46aca07e5984bfda3b284bb70383b11840cb3436 /include
parent0dadf17ab705fa2f96f0513278672978d73601ed (diff)
downloadqpdf-0b05111db80469d3f556209bfd856af1fda9b142.tar.zst
Implement helper class for interactive forms
Diffstat (limited to 'include')
-rw-r--r--include/qpdf/QPDFAcroFormDocumentHelper.hh165
-rw-r--r--include/qpdf/QPDFAnnotationObjectHelper.hh86
-rw-r--r--include/qpdf/QPDFFormFieldObjectHelper.hh133
-rw-r--r--include/qpdf/QPDFPageObjectHelper.hh8
4 files changed, 392 insertions, 0 deletions
diff --git a/include/qpdf/QPDFAcroFormDocumentHelper.hh b/include/qpdf/QPDFAcroFormDocumentHelper.hh
new file mode 100644
index 00000000..d786fff4
--- /dev/null
+++ b/include/qpdf/QPDFAcroFormDocumentHelper.hh
@@ -0,0 +1,165 @@
+// Copyright (c) 2005-2018 Jay Berkenbilt
+//
+// This file is part of qpdf.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Versions of qpdf prior to version 7 were released under the terms
+// of version 2.0 of the Artistic License. At your option, you may
+// continue to consider qpdf to be licensed under those terms. Please
+// see the manual for additional information.
+
+#ifndef __QPDFACROFORMDOCUMENTHELPER_HH__
+#define __QPDFACROFORMDOCUMENTHELPER_HH__
+
+// This document helper is intended to help with operations on
+// interactive forms. Here are the key things to know:
+
+// * The PDF specification talks about interactive forms and also
+// about form XObjects. While form XObjects appear in parts of
+// interactive forms, this class is concerned about interactive
+// forms, not form XObjects.
+//
+// * Interactive forms are discussed in the PDF Specification (ISO PDF
+// 32000-1:2008) section 12.7. Also relevant is the section about
+// Widget annotations. Annotations are discussed in section 12.5
+// with annotation dictionaries discussed in 12.5.1. Widget
+// annotations are discussed specifically in section 12.5.6.19.
+//
+// * What you need to know about the structure of interactive forms in
+// PDF files:
+//
+// - The document catalog contains the key "/AcroForm" which
+// contains a list of fields. Fields are represented as a tree
+// structure much like pages. Nodes in the fields tree may contain
+// other fields. Fields may inherit values of many of their
+// attributes from ancestors in the tree.
+//
+// - Fields may also have children that are widget annotations. As a
+// special case, and a cause of considerable confusion, if a field
+// has a single annotation as a child, the annotation dictionary
+// may be merged with the field dictionary. In that case, the
+// field and the annotation are in the same object. Note that,
+// while field dictionary attributes are inherited, annotation
+// dictionary attributes are not.
+//
+// - A page dictionary contains a key called "/Annots" which
+// contains a simple list of annotations. For any given annotation
+// of subtype "/Widget", you should encounter that annotation in
+// the "/Annots" dictionary of a page, and you should also be able
+// to reach it by traversing through the "/AcroForm" dictionary
+// from the document catalog. In the simplest case (and also a
+// very common case), a form field's widget annotation will be
+// merged with the field object, and the object will appear
+// directly both under "/Annots" in the page dictionary and under
+// "/Fields" in the "/AcroForm" dictionary. In a more complex
+// case, you may have to trace through various "/Kids" elements in
+// the "/AcroForm" field entry until you find the annotation
+// dictionary.
+
+
+#include <qpdf/QPDFDocumentHelper.hh>
+
+#include <qpdf/DLL.h>
+
+#include <qpdf/QPDFAnnotationObjectHelper.hh>
+#include <qpdf/QPDFFormFieldObjectHelper.hh>
+#include <qpdf/QPDFPageObjectHelper.hh>
+
+#include <map>
+#include <set>
+#include <vector>
+
+class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
+{
+ public:
+ QPDFAcroFormDocumentHelper(QPDF&);
+
+ // This class lazily creates an internal cache of the mapping
+ // among form fields, annotations, and pages. Methods within this
+ // class preserve the validity of this cache. However, if you
+ // modify pages' annotation dictionaries, the document's /AcroForm
+ // dictionary, or any form fields manually in a way that alters
+ // the association between forms, fields, annotations, and pages,
+ // it may cause this cache to become invalid. This method marks
+ // the cache invalid and forces it to be regenerated the next time
+ // it is needed.
+ QPDF_DLL
+ void invalidateCache();
+
+ QPDF_DLL
+ bool
+ hasAcroForm();
+
+ // Return a vector of all terminal fields in a document. Terminal
+ // fields are fields that have no children that are also fields.
+ // Terminal fields may still have children that are annotations.
+ // Intermediate nodes in the fields tree are not included in this
+ // list, but you can still reach them through the getParent method
+ // of the field object helper.
+ QPDF_DLL
+ std::vector<QPDFFormFieldObjectHelper>
+ getFormFields();
+
+ // Return the annotations associated with a terminal field. Note
+ // that in the case of a field having a single annotation, the
+ // underlying object will typically be the same as the underlying
+ // object for the field.
+ QPDF_DLL
+ std::vector<QPDFAnnotationObjectHelper>
+ getAnnotationsForField(QPDFFormFieldObjectHelper);
+
+ // Return annotations of subtype /Widget for a page.
+ QPDF_DLL
+ std::vector<QPDFAnnotationObjectHelper>
+ getWidgetAnnotationsForPage(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
+ // this is not always the case. Note that if you call this method
+ // with an annotation that is not a widget annotation, there will
+ // not be an associated field, and this method will raise an
+ // exception.
+ QPDF_DLL
+ QPDFFormFieldObjectHelper
+ getFieldForAnnotation(QPDFAnnotationObjectHelper);
+
+ private:
+ void analyze();
+ void traverseField(QPDFObjectHandle field,
+ QPDFObjectHandle parent,
+ int depth, std::set<QPDFObjGen>& visited);
+
+ class Members
+ {
+ friend class QPDFAcroFormDocumentHelper;
+
+ public:
+ ~Members();
+
+ private:
+ Members();
+ Members(Members const&);
+
+ bool cache_valid;
+ std::map<QPDFObjGen,
+ std::vector<QPDFAnnotationObjectHelper>
+ > field_to_annotations;
+ std::map<QPDFObjGen, QPDFFormFieldObjectHelper> annotation_to_field;
+ };
+
+ PointerHolder<Members> m;
+};
+
+#endif // __QPDFACROFORMDOCUMENTHELPER_HH__
diff --git a/include/qpdf/QPDFAnnotationObjectHelper.hh b/include/qpdf/QPDFAnnotationObjectHelper.hh
new file mode 100644
index 00000000..d64388da
--- /dev/null
+++ b/include/qpdf/QPDFAnnotationObjectHelper.hh
@@ -0,0 +1,86 @@
+// Copyright (c) 2005-2018 Jay Berkenbilt
+//
+// This file is part of qpdf.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Versions of qpdf prior to version 7 were released under the terms
+// of version 2.0 of the Artistic License. At your option, you may
+// continue to consider qpdf to be licensed under those terms. Please
+// see the manual for additional information.
+
+#ifndef __QPDFANNOTATIONOBJECTHELPER_HH__
+#define __QPDFANNOTATIONOBJECTHELPER_HH__
+
+#include <qpdf/QPDFObjectHelper.hh>
+
+#include <qpdf/DLL.h>
+
+class QPDFAnnotationObjectHelper: public QPDFObjectHelper
+{
+ public:
+ QPDFAnnotationObjectHelper(QPDFObjectHandle);
+
+ // This class provides helper methods for certain types of
+ // annotations. At its introduction, it only supports Widget
+ // annotations, but other types of annotations may be supported in
+ // the future. For additional information about interactive forms,
+ // please see the comments at the top of
+ // QPDFAcroFormDocumentHelper.hh.
+
+ // Return the subtype of the annotation as a string (e.g.
+ // "/Widget"). Returns the empty string if the subtype (which is
+ // required by the spec) is missing.
+ QPDF_DLL
+ std::string getSubtype();
+
+ QPDF_DLL
+ QPDFObjectHandle::Rectangle getRect();
+
+ QPDF_DLL
+ QPDFObjectHandle getAppearanceDictionary();
+
+ // Return the appearance state as given in "/AS", or the empty
+ // string if none is given.
+ QPDF_DLL
+ std::string getAppearanceState();
+
+ // Return a specific stream. "which" may be one of "/N", "/R", or
+ // "/D" to indicate the normal, rollover, or down appearance
+ // stream. (Any value may be passed to "which"; if an appearance
+ // stream of that name exists, it will be returned.) If the value
+ // associated with "which" in the appearance dictionary is a
+ // subdictionary, an appearance state may be specified to select
+ // which appearance stream is desired. If not specified, the
+ // appearance state in "/AS" will used.
+ QPDF_DLL
+ QPDFObjectHandle getAppearanceStream(std::string const& which,
+ std::string const& state = "");
+
+ private:
+ class Members
+ {
+ friend class QPDFPageObjectHelper;
+
+ public:
+ ~Members();
+
+ private:
+ Members();
+ Members(Members const&);
+ };
+
+ PointerHolder<Members> m;
+};
+
+#endif // __QPDFANNOTATIONOBJECTHELPER_HH__
diff --git a/include/qpdf/QPDFFormFieldObjectHelper.hh b/include/qpdf/QPDFFormFieldObjectHelper.hh
new file mode 100644
index 00000000..b45955a3
--- /dev/null
+++ b/include/qpdf/QPDFFormFieldObjectHelper.hh
@@ -0,0 +1,133 @@
+// Copyright (c) 2005-2018 Jay Berkenbilt
+//
+// This file is part of qpdf.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Versions of qpdf prior to version 7 were released under the terms
+// of version 2.0 of the Artistic License. At your option, you may
+// continue to consider qpdf to be licensed under those terms. Please
+// see the manual for additional information.
+
+#ifndef __QPDFFORMFIELDOBJECTHELPER_HH__
+#define __QPDFFORMFIELDOBJECTHELPER_HH__
+
+// This object helper helps with form fields for interactive forms.
+// Please see comments in QPDFAcroFormDocumentHelper.hh for additional
+// details.
+
+#include <qpdf/QPDFObjectHelper.hh>
+
+#include <qpdf/DLL.h>
+
+class QPDFFormFieldObjectHelper: public QPDFObjectHelper
+{
+ public:
+ QPDFFormFieldObjectHelper();
+ QPDFFormFieldObjectHelper(QPDFObjectHandle);
+
+ QPDF_DLL
+ bool isNull();
+
+ // Return the field's parent. A form field object helper whose
+ // underlying object is null is returned if there is no parent.
+ // This condition may be tested by calling isNull().
+ QPDF_DLL
+ QPDFFormFieldObjectHelper getParent();
+
+ // Get a field value, possibly inheriting the value from an
+ // ancestor node.
+ QPDF_DLL
+ QPDFObjectHandle getInheritableFieldValue(std::string const& name);
+
+ // Get an inherited field value as a string. If it is not a
+ // string, silently return the empty string.
+ QPDF_DLL
+ std::string getInheritableFieldValueAsString(std::string const& name);
+
+ // Get an inherited field value of type name as a string
+ // representing the name. If it is not a name, silently return
+ // the empty string.
+ QPDF_DLL
+ std::string getInheritableFieldValueAsName(std::string const& name);
+
+ // Returns the value of /FT if present, otherwise returns the
+ // empty string.
+ QPDF_DLL
+ std::string getFieldType();
+
+ QPDF_DLL
+ std::string getFullyQualifiedName();
+
+ QPDF_DLL
+ std::string getPartialName();
+
+ // Return the alternative field name (/TU), which is the field
+ // name intended to be presented to users. If not present, fall
+ // back to the fully qualified name.
+ QPDF_DLL
+ std::string getAlternativeName();
+
+ // Return the mapping field name (/TM). If not present, fall back
+ // to the alternative name, then to the partial name.
+ QPDF_DLL
+ std::string getMappingName();
+
+ QPDF_DLL
+ QPDFObjectHandle getValue();
+
+ // Return the field's value as a string. If this is called with a
+ // field whose value is not a string, the empty string will be
+ // silently returned.
+ QPDF_DLL
+ std::string getValueAsString();
+
+ QPDF_DLL
+ QPDFObjectHandle getDefaultValue();
+
+ // Return the field's default value as a string. If this is called
+ // with a field whose value is not a string, the empty string will
+ // be silently returned.
+ QPDF_DLL
+ std::string getDefaultValueAsString();
+
+ // Return the default appearance string, taking inheritance from
+ // the field tree into account. Returns the empty string if the
+ // default appearance string is not available (because it's
+ // erroneously absent or because this is not a variable text
+ // field).
+ QPDF_DLL
+ std::string getDefaultAppearance();
+
+ // Return the quadding value, taking inheritance from the field
+ // tree into account. Returns 0 if quadding is not specified.
+ QPDF_DLL
+ int getQuadding();
+
+ private:
+ class Members
+ {
+ friend class QPDFFormFieldObjectHelper;
+
+ public:
+ ~Members();
+
+ private:
+ Members();
+ Members(Members const&);
+ };
+
+ PointerHolder<Members> m;
+};
+
+#endif // __QPDFFORMFIELDOBJECTHELPER_HH__
diff --git a/include/qpdf/QPDFPageObjectHelper.hh b/include/qpdf/QPDFPageObjectHelper.hh
index 2d307f34..9226a748 100644
--- a/include/qpdf/QPDFPageObjectHelper.hh
+++ b/include/qpdf/QPDFPageObjectHelper.hh
@@ -23,6 +23,7 @@
#define __QPDFPAGEOBJECTHELPER_HH__
#include <qpdf/QPDFObjectHelper.hh>
+#include <qpdf/QPDFAnnotationObjectHelper.hh>
#include <qpdf/DLL.h>
@@ -43,6 +44,13 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
QPDF_DLL
std::map<std::string, QPDFObjectHandle> getPageImages();
+ // Return the annotations in the page's "/Annots" list, if any. If
+ // only_subtype is non-empty, only include annotations of the
+ // given subtype.
+ QPDF_DLL
+ std::vector<QPDFAnnotationObjectHelper> getAnnotations(
+ std::string const& only_subtype = "");
+
// Returns a vector of stream objects representing the content
// streams for the given page. This routine allows the caller to
// not care whether there are one or more than one content streams