Commit 0b05111db80469d3f556209bfd856af1fda9b142
1 parent
0dadf17a
Implement helper class for interactive forms
Showing
27 changed files
with
14524 additions
and
0 deletions
ChangeLog
| 1 | 2018-06-20 Jay Berkenbilt <ejb@ql.org> | 1 | 2018-06-20 Jay Berkenbilt <ejb@ql.org> |
| 2 | 2 | ||
| 3 | + * Added new classes QPDFAcroFormDocumentHelper, | ||
| 4 | + QPDFFormFieldObjectHelper, and QPDFAnnotationObjectHelper to | ||
| 5 | + assist with working with interactive forms in PDF files. At | ||
| 6 | + present, API methods for reading forms, form fields, and widget | ||
| 7 | + annotations have been added. It is likely that some additional | ||
| 8 | + methods for modifying forms will be added in the future. Note that | ||
| 9 | + qpdf remains a library whose function is primarily focused around | ||
| 10 | + document structure and metadata rather than content. As such, it | ||
| 11 | + is not expected that qpdf will have higher level APIs for | ||
| 12 | + generating form contents, but qpdf will hopefully gain the | ||
| 13 | + capability to deal with the bookkeeping aspects of wiring up all | ||
| 14 | + the objects, which could make it a useful library for other | ||
| 15 | + software that works with PDF interactive forms. PDF forms are | ||
| 16 | + complex, and the terminology around them is confusing. Please see | ||
| 17 | + comments at the top of QPDFAcroFormDocumentHelper.hh for | ||
| 18 | + additional discussion. | ||
| 19 | + | ||
| 3 | * Added new classes QPDFPageDocumentHelper and QPDFPageObjctHelper | 20 | * Added new classes QPDFPageDocumentHelper and QPDFPageObjctHelper |
| 4 | for page-level API functions. These classes introduce a new API | 21 | for page-level API functions. These classes introduce a new API |
| 5 | pattern of document helpers and object helpers in qpdf. The helper | 22 | pattern of document helpers and object helpers in qpdf. The helper |
include/qpdf/QPDFAcroFormDocumentHelper.hh
0 → 100644
| 1 | +// Copyright (c) 2005-2018 Jay Berkenbilt | ||
| 2 | +// | ||
| 3 | +// This file is part of qpdf. | ||
| 4 | +// | ||
| 5 | +// Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | +// you may not use this file except in compliance with the License. | ||
| 7 | +// You may obtain a copy of the License at | ||
| 8 | +// | ||
| 9 | +// http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | +// | ||
| 11 | +// Unless required by applicable law or agreed to in writing, software | ||
| 12 | +// distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | +// See the License for the specific language governing permissions and | ||
| 15 | +// limitations under the License. | ||
| 16 | +// | ||
| 17 | +// Versions of qpdf prior to version 7 were released under the terms | ||
| 18 | +// of version 2.0 of the Artistic License. At your option, you may | ||
| 19 | +// continue to consider qpdf to be licensed under those terms. Please | ||
| 20 | +// see the manual for additional information. | ||
| 21 | + | ||
| 22 | +#ifndef __QPDFACROFORMDOCUMENTHELPER_HH__ | ||
| 23 | +#define __QPDFACROFORMDOCUMENTHELPER_HH__ | ||
| 24 | + | ||
| 25 | +// This document helper is intended to help with operations on | ||
| 26 | +// interactive forms. Here are the key things to know: | ||
| 27 | + | ||
| 28 | +// * The PDF specification talks about interactive forms and also | ||
| 29 | +// about form XObjects. While form XObjects appear in parts of | ||
| 30 | +// interactive forms, this class is concerned about interactive | ||
| 31 | +// forms, not form XObjects. | ||
| 32 | +// | ||
| 33 | +// * Interactive forms are discussed in the PDF Specification (ISO PDF | ||
| 34 | +// 32000-1:2008) section 12.7. Also relevant is the section about | ||
| 35 | +// Widget annotations. Annotations are discussed in section 12.5 | ||
| 36 | +// with annotation dictionaries discussed in 12.5.1. Widget | ||
| 37 | +// annotations are discussed specifically in section 12.5.6.19. | ||
| 38 | +// | ||
| 39 | +// * What you need to know about the structure of interactive forms in | ||
| 40 | +// PDF files: | ||
| 41 | +// | ||
| 42 | +// - The document catalog contains the key "/AcroForm" which | ||
| 43 | +// contains a list of fields. Fields are represented as a tree | ||
| 44 | +// structure much like pages. Nodes in the fields tree may contain | ||
| 45 | +// other fields. Fields may inherit values of many of their | ||
| 46 | +// attributes from ancestors in the tree. | ||
| 47 | +// | ||
| 48 | +// - Fields may also have children that are widget annotations. As a | ||
| 49 | +// special case, and a cause of considerable confusion, if a field | ||
| 50 | +// has a single annotation as a child, the annotation dictionary | ||
| 51 | +// may be merged with the field dictionary. In that case, the | ||
| 52 | +// field and the annotation are in the same object. Note that, | ||
| 53 | +// while field dictionary attributes are inherited, annotation | ||
| 54 | +// dictionary attributes are not. | ||
| 55 | +// | ||
| 56 | +// - A page dictionary contains a key called "/Annots" which | ||
| 57 | +// contains a simple list of annotations. For any given annotation | ||
| 58 | +// of subtype "/Widget", you should encounter that annotation in | ||
| 59 | +// the "/Annots" dictionary of a page, and you should also be able | ||
| 60 | +// to reach it by traversing through the "/AcroForm" dictionary | ||
| 61 | +// from the document catalog. In the simplest case (and also a | ||
| 62 | +// very common case), a form field's widget annotation will be | ||
| 63 | +// merged with the field object, and the object will appear | ||
| 64 | +// directly both under "/Annots" in the page dictionary and under | ||
| 65 | +// "/Fields" in the "/AcroForm" dictionary. In a more complex | ||
| 66 | +// case, you may have to trace through various "/Kids" elements in | ||
| 67 | +// the "/AcroForm" field entry until you find the annotation | ||
| 68 | +// dictionary. | ||
| 69 | + | ||
| 70 | + | ||
| 71 | +#include <qpdf/QPDFDocumentHelper.hh> | ||
| 72 | + | ||
| 73 | +#include <qpdf/DLL.h> | ||
| 74 | + | ||
| 75 | +#include <qpdf/QPDFAnnotationObjectHelper.hh> | ||
| 76 | +#include <qpdf/QPDFFormFieldObjectHelper.hh> | ||
| 77 | +#include <qpdf/QPDFPageObjectHelper.hh> | ||
| 78 | + | ||
| 79 | +#include <map> | ||
| 80 | +#include <set> | ||
| 81 | +#include <vector> | ||
| 82 | + | ||
| 83 | +class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper | ||
| 84 | +{ | ||
| 85 | + public: | ||
| 86 | + QPDFAcroFormDocumentHelper(QPDF&); | ||
| 87 | + | ||
| 88 | + // This class lazily creates an internal cache of the mapping | ||
| 89 | + // among form fields, annotations, and pages. Methods within this | ||
| 90 | + // class preserve the validity of this cache. However, if you | ||
| 91 | + // modify pages' annotation dictionaries, the document's /AcroForm | ||
| 92 | + // dictionary, or any form fields manually in a way that alters | ||
| 93 | + // the association between forms, fields, annotations, and pages, | ||
| 94 | + // it may cause this cache to become invalid. This method marks | ||
| 95 | + // the cache invalid and forces it to be regenerated the next time | ||
| 96 | + // it is needed. | ||
| 97 | + QPDF_DLL | ||
| 98 | + void invalidateCache(); | ||
| 99 | + | ||
| 100 | + QPDF_DLL | ||
| 101 | + bool | ||
| 102 | + hasAcroForm(); | ||
| 103 | + | ||
| 104 | + // Return a vector of all terminal fields in a document. Terminal | ||
| 105 | + // fields are fields that have no children that are also fields. | ||
| 106 | + // Terminal fields may still have children that are annotations. | ||
| 107 | + // Intermediate nodes in the fields tree are not included in this | ||
| 108 | + // list, but you can still reach them through the getParent method | ||
| 109 | + // of the field object helper. | ||
| 110 | + QPDF_DLL | ||
| 111 | + std::vector<QPDFFormFieldObjectHelper> | ||
| 112 | + getFormFields(); | ||
| 113 | + | ||
| 114 | + // Return the annotations associated with a terminal field. Note | ||
| 115 | + // that in the case of a field having a single annotation, the | ||
| 116 | + // underlying object will typically be the same as the underlying | ||
| 117 | + // object for the field. | ||
| 118 | + QPDF_DLL | ||
| 119 | + std::vector<QPDFAnnotationObjectHelper> | ||
| 120 | + getAnnotationsForField(QPDFFormFieldObjectHelper); | ||
| 121 | + | ||
| 122 | + // Return annotations of subtype /Widget for a page. | ||
| 123 | + QPDF_DLL | ||
| 124 | + std::vector<QPDFAnnotationObjectHelper> | ||
| 125 | + getWidgetAnnotationsForPage(QPDFPageObjectHelper); | ||
| 126 | + | ||
| 127 | + // Return the terminal field that is associated with this | ||
| 128 | + // annotation. If the annotation dictionary is merged with the | ||
| 129 | + // field dictionary, the underlying object will be the same, but | ||
| 130 | + // this is not always the case. Note that if you call this method | ||
| 131 | + // with an annotation that is not a widget annotation, there will | ||
| 132 | + // not be an associated field, and this method will raise an | ||
| 133 | + // exception. | ||
| 134 | + QPDF_DLL | ||
| 135 | + QPDFFormFieldObjectHelper | ||
| 136 | + getFieldForAnnotation(QPDFAnnotationObjectHelper); | ||
| 137 | + | ||
| 138 | + private: | ||
| 139 | + void analyze(); | ||
| 140 | + void traverseField(QPDFObjectHandle field, | ||
| 141 | + QPDFObjectHandle parent, | ||
| 142 | + int depth, std::set<QPDFObjGen>& visited); | ||
| 143 | + | ||
| 144 | + class Members | ||
| 145 | + { | ||
| 146 | + friend class QPDFAcroFormDocumentHelper; | ||
| 147 | + | ||
| 148 | + public: | ||
| 149 | + ~Members(); | ||
| 150 | + | ||
| 151 | + private: | ||
| 152 | + Members(); | ||
| 153 | + Members(Members const&); | ||
| 154 | + | ||
| 155 | + bool cache_valid; | ||
| 156 | + std::map<QPDFObjGen, | ||
| 157 | + std::vector<QPDFAnnotationObjectHelper> | ||
| 158 | + > field_to_annotations; | ||
| 159 | + std::map<QPDFObjGen, QPDFFormFieldObjectHelper> annotation_to_field; | ||
| 160 | + }; | ||
| 161 | + | ||
| 162 | + PointerHolder<Members> m; | ||
| 163 | +}; | ||
| 164 | + | ||
| 165 | +#endif // __QPDFACROFORMDOCUMENTHELPER_HH__ |
include/qpdf/QPDFAnnotationObjectHelper.hh
0 → 100644
| 1 | +// Copyright (c) 2005-2018 Jay Berkenbilt | ||
| 2 | +// | ||
| 3 | +// This file is part of qpdf. | ||
| 4 | +// | ||
| 5 | +// Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | +// you may not use this file except in compliance with the License. | ||
| 7 | +// You may obtain a copy of the License at | ||
| 8 | +// | ||
| 9 | +// http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | +// | ||
| 11 | +// Unless required by applicable law or agreed to in writing, software | ||
| 12 | +// distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | +// See the License for the specific language governing permissions and | ||
| 15 | +// limitations under the License. | ||
| 16 | +// | ||
| 17 | +// Versions of qpdf prior to version 7 were released under the terms | ||
| 18 | +// of version 2.0 of the Artistic License. At your option, you may | ||
| 19 | +// continue to consider qpdf to be licensed under those terms. Please | ||
| 20 | +// see the manual for additional information. | ||
| 21 | + | ||
| 22 | +#ifndef __QPDFANNOTATIONOBJECTHELPER_HH__ | ||
| 23 | +#define __QPDFANNOTATIONOBJECTHELPER_HH__ | ||
| 24 | + | ||
| 25 | +#include <qpdf/QPDFObjectHelper.hh> | ||
| 26 | + | ||
| 27 | +#include <qpdf/DLL.h> | ||
| 28 | + | ||
| 29 | +class QPDFAnnotationObjectHelper: public QPDFObjectHelper | ||
| 30 | +{ | ||
| 31 | + public: | ||
| 32 | + QPDFAnnotationObjectHelper(QPDFObjectHandle); | ||
| 33 | + | ||
| 34 | + // This class provides helper methods for certain types of | ||
| 35 | + // annotations. At its introduction, it only supports Widget | ||
| 36 | + // annotations, but other types of annotations may be supported in | ||
| 37 | + // the future. For additional information about interactive forms, | ||
| 38 | + // please see the comments at the top of | ||
| 39 | + // QPDFAcroFormDocumentHelper.hh. | ||
| 40 | + | ||
| 41 | + // Return the subtype of the annotation as a string (e.g. | ||
| 42 | + // "/Widget"). Returns the empty string if the subtype (which is | ||
| 43 | + // required by the spec) is missing. | ||
| 44 | + QPDF_DLL | ||
| 45 | + std::string getSubtype(); | ||
| 46 | + | ||
| 47 | + QPDF_DLL | ||
| 48 | + QPDFObjectHandle::Rectangle getRect(); | ||
| 49 | + | ||
| 50 | + QPDF_DLL | ||
| 51 | + QPDFObjectHandle getAppearanceDictionary(); | ||
| 52 | + | ||
| 53 | + // Return the appearance state as given in "/AS", or the empty | ||
| 54 | + // string if none is given. | ||
| 55 | + QPDF_DLL | ||
| 56 | + std::string getAppearanceState(); | ||
| 57 | + | ||
| 58 | + // Return a specific stream. "which" may be one of "/N", "/R", or | ||
| 59 | + // "/D" to indicate the normal, rollover, or down appearance | ||
| 60 | + // stream. (Any value may be passed to "which"; if an appearance | ||
| 61 | + // stream of that name exists, it will be returned.) If the value | ||
| 62 | + // associated with "which" in the appearance dictionary is a | ||
| 63 | + // subdictionary, an appearance state may be specified to select | ||
| 64 | + // which appearance stream is desired. If not specified, the | ||
| 65 | + // appearance state in "/AS" will used. | ||
| 66 | + QPDF_DLL | ||
| 67 | + QPDFObjectHandle getAppearanceStream(std::string const& which, | ||
| 68 | + std::string const& state = ""); | ||
| 69 | + | ||
| 70 | + private: | ||
| 71 | + class Members | ||
| 72 | + { | ||
| 73 | + friend class QPDFPageObjectHelper; | ||
| 74 | + | ||
| 75 | + public: | ||
| 76 | + ~Members(); | ||
| 77 | + | ||
| 78 | + private: | ||
| 79 | + Members(); | ||
| 80 | + Members(Members const&); | ||
| 81 | + }; | ||
| 82 | + | ||
| 83 | + PointerHolder<Members> m; | ||
| 84 | +}; | ||
| 85 | + | ||
| 86 | +#endif // __QPDFANNOTATIONOBJECTHELPER_HH__ |
include/qpdf/QPDFFormFieldObjectHelper.hh
0 → 100644
| 1 | +// Copyright (c) 2005-2018 Jay Berkenbilt | ||
| 2 | +// | ||
| 3 | +// This file is part of qpdf. | ||
| 4 | +// | ||
| 5 | +// Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | +// you may not use this file except in compliance with the License. | ||
| 7 | +// You may obtain a copy of the License at | ||
| 8 | +// | ||
| 9 | +// http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | +// | ||
| 11 | +// Unless required by applicable law or agreed to in writing, software | ||
| 12 | +// distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | +// See the License for the specific language governing permissions and | ||
| 15 | +// limitations under the License. | ||
| 16 | +// | ||
| 17 | +// Versions of qpdf prior to version 7 were released under the terms | ||
| 18 | +// of version 2.0 of the Artistic License. At your option, you may | ||
| 19 | +// continue to consider qpdf to be licensed under those terms. Please | ||
| 20 | +// see the manual for additional information. | ||
| 21 | + | ||
| 22 | +#ifndef __QPDFFORMFIELDOBJECTHELPER_HH__ | ||
| 23 | +#define __QPDFFORMFIELDOBJECTHELPER_HH__ | ||
| 24 | + | ||
| 25 | +// This object helper helps with form fields for interactive forms. | ||
| 26 | +// Please see comments in QPDFAcroFormDocumentHelper.hh for additional | ||
| 27 | +// details. | ||
| 28 | + | ||
| 29 | +#include <qpdf/QPDFObjectHelper.hh> | ||
| 30 | + | ||
| 31 | +#include <qpdf/DLL.h> | ||
| 32 | + | ||
| 33 | +class QPDFFormFieldObjectHelper: public QPDFObjectHelper | ||
| 34 | +{ | ||
| 35 | + public: | ||
| 36 | + QPDFFormFieldObjectHelper(); | ||
| 37 | + QPDFFormFieldObjectHelper(QPDFObjectHandle); | ||
| 38 | + | ||
| 39 | + QPDF_DLL | ||
| 40 | + bool isNull(); | ||
| 41 | + | ||
| 42 | + // Return the field's parent. A form field object helper whose | ||
| 43 | + // underlying object is null is returned if there is no parent. | ||
| 44 | + // This condition may be tested by calling isNull(). | ||
| 45 | + QPDF_DLL | ||
| 46 | + QPDFFormFieldObjectHelper getParent(); | ||
| 47 | + | ||
| 48 | + // Get a field value, possibly inheriting the value from an | ||
| 49 | + // ancestor node. | ||
| 50 | + QPDF_DLL | ||
| 51 | + QPDFObjectHandle getInheritableFieldValue(std::string const& name); | ||
| 52 | + | ||
| 53 | + // Get an inherited field value as a string. If it is not a | ||
| 54 | + // string, silently return the empty string. | ||
| 55 | + QPDF_DLL | ||
| 56 | + std::string getInheritableFieldValueAsString(std::string const& name); | ||
| 57 | + | ||
| 58 | + // Get an inherited field value of type name as a string | ||
| 59 | + // representing the name. If it is not a name, silently return | ||
| 60 | + // the empty string. | ||
| 61 | + QPDF_DLL | ||
| 62 | + std::string getInheritableFieldValueAsName(std::string const& name); | ||
| 63 | + | ||
| 64 | + // Returns the value of /FT if present, otherwise returns the | ||
| 65 | + // empty string. | ||
| 66 | + QPDF_DLL | ||
| 67 | + std::string getFieldType(); | ||
| 68 | + | ||
| 69 | + QPDF_DLL | ||
| 70 | + std::string getFullyQualifiedName(); | ||
| 71 | + | ||
| 72 | + QPDF_DLL | ||
| 73 | + std::string getPartialName(); | ||
| 74 | + | ||
| 75 | + // Return the alternative field name (/TU), which is the field | ||
| 76 | + // name intended to be presented to users. If not present, fall | ||
| 77 | + // back to the fully qualified name. | ||
| 78 | + QPDF_DLL | ||
| 79 | + std::string getAlternativeName(); | ||
| 80 | + | ||
| 81 | + // Return the mapping field name (/TM). If not present, fall back | ||
| 82 | + // to the alternative name, then to the partial name. | ||
| 83 | + QPDF_DLL | ||
| 84 | + std::string getMappingName(); | ||
| 85 | + | ||
| 86 | + QPDF_DLL | ||
| 87 | + QPDFObjectHandle getValue(); | ||
| 88 | + | ||
| 89 | + // Return the field's value as a string. If this is called with a | ||
| 90 | + // field whose value is not a string, the empty string will be | ||
| 91 | + // silently returned. | ||
| 92 | + QPDF_DLL | ||
| 93 | + std::string getValueAsString(); | ||
| 94 | + | ||
| 95 | + QPDF_DLL | ||
| 96 | + QPDFObjectHandle getDefaultValue(); | ||
| 97 | + | ||
| 98 | + // Return the field's default value as a string. If this is called | ||
| 99 | + // with a field whose value is not a string, the empty string will | ||
| 100 | + // be silently returned. | ||
| 101 | + QPDF_DLL | ||
| 102 | + std::string getDefaultValueAsString(); | ||
| 103 | + | ||
| 104 | + // Return the default appearance string, taking inheritance from | ||
| 105 | + // the field tree into account. Returns the empty string if the | ||
| 106 | + // default appearance string is not available (because it's | ||
| 107 | + // erroneously absent or because this is not a variable text | ||
| 108 | + // field). | ||
| 109 | + QPDF_DLL | ||
| 110 | + std::string getDefaultAppearance(); | ||
| 111 | + | ||
| 112 | + // Return the quadding value, taking inheritance from the field | ||
| 113 | + // tree into account. Returns 0 if quadding is not specified. | ||
| 114 | + QPDF_DLL | ||
| 115 | + int getQuadding(); | ||
| 116 | + | ||
| 117 | + private: | ||
| 118 | + class Members | ||
| 119 | + { | ||
| 120 | + friend class QPDFFormFieldObjectHelper; | ||
| 121 | + | ||
| 122 | + public: | ||
| 123 | + ~Members(); | ||
| 124 | + | ||
| 125 | + private: | ||
| 126 | + Members(); | ||
| 127 | + Members(Members const&); | ||
| 128 | + }; | ||
| 129 | + | ||
| 130 | + PointerHolder<Members> m; | ||
| 131 | +}; | ||
| 132 | + | ||
| 133 | +#endif // __QPDFFORMFIELDOBJECTHELPER_HH__ |
include/qpdf/QPDFPageObjectHelper.hh
| @@ -23,6 +23,7 @@ | @@ -23,6 +23,7 @@ | ||
| 23 | #define __QPDFPAGEOBJECTHELPER_HH__ | 23 | #define __QPDFPAGEOBJECTHELPER_HH__ |
| 24 | 24 | ||
| 25 | #include <qpdf/QPDFObjectHelper.hh> | 25 | #include <qpdf/QPDFObjectHelper.hh> |
| 26 | +#include <qpdf/QPDFAnnotationObjectHelper.hh> | ||
| 26 | 27 | ||
| 27 | #include <qpdf/DLL.h> | 28 | #include <qpdf/DLL.h> |
| 28 | 29 | ||
| @@ -43,6 +44,13 @@ class QPDFPageObjectHelper: public QPDFObjectHelper | @@ -43,6 +44,13 @@ class QPDFPageObjectHelper: public QPDFObjectHelper | ||
| 43 | QPDF_DLL | 44 | QPDF_DLL |
| 44 | std::map<std::string, QPDFObjectHandle> getPageImages(); | 45 | std::map<std::string, QPDFObjectHandle> getPageImages(); |
| 45 | 46 | ||
| 47 | + // Return the annotations in the page's "/Annots" list, if any. If | ||
| 48 | + // only_subtype is non-empty, only include annotations of the | ||
| 49 | + // given subtype. | ||
| 50 | + QPDF_DLL | ||
| 51 | + std::vector<QPDFAnnotationObjectHelper> getAnnotations( | ||
| 52 | + std::string const& only_subtype = ""); | ||
| 53 | + | ||
| 46 | // Returns a vector of stream objects representing the content | 54 | // Returns a vector of stream objects representing the content |
| 47 | // streams for the given page. This routine allows the caller to | 55 | // streams for the given page. This routine allows the caller to |
| 48 | // not care whether there are one or more than one content streams | 56 | // not care whether there are one or more than one content streams |
libqpdf/QPDFAcroFormDocumentHelper.cc
0 → 100644
| 1 | +#include <qpdf/QPDFAcroFormDocumentHelper.hh> | ||
| 2 | + | ||
| 3 | +#include <qpdf/QTC.hh> | ||
| 4 | +#include <qpdf/QPDFPageDocumentHelper.hh> | ||
| 5 | + | ||
| 6 | +QPDFAcroFormDocumentHelper::Members::~Members() | ||
| 7 | +{ | ||
| 8 | +} | ||
| 9 | + | ||
| 10 | +QPDFAcroFormDocumentHelper::Members::Members() : | ||
| 11 | + cache_valid(false) | ||
| 12 | +{ | ||
| 13 | +} | ||
| 14 | + | ||
| 15 | +QPDFAcroFormDocumentHelper::QPDFAcroFormDocumentHelper(QPDF& qpdf) : | ||
| 16 | + QPDFDocumentHelper(qpdf), | ||
| 17 | + m(new Members()) | ||
| 18 | +{ | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +void | ||
| 22 | +QPDFAcroFormDocumentHelper::invalidateCache() | ||
| 23 | +{ | ||
| 24 | + this->m->cache_valid = false; | ||
| 25 | + this->m->field_to_annotations.clear(); | ||
| 26 | + this->m->annotation_to_field.clear(); | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +bool | ||
| 30 | +QPDFAcroFormDocumentHelper::hasAcroForm() | ||
| 31 | +{ | ||
| 32 | + return this->qpdf.getRoot().hasKey("/AcroForm"); | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +std::vector<QPDFFormFieldObjectHelper> | ||
| 36 | +QPDFAcroFormDocumentHelper::getFormFields() | ||
| 37 | +{ | ||
| 38 | + analyze(); | ||
| 39 | + std::vector<QPDFFormFieldObjectHelper> result; | ||
| 40 | + for (std::map<QPDFObjGen, | ||
| 41 | + std::vector<QPDFAnnotationObjectHelper> >::iterator iter = | ||
| 42 | + this->m->field_to_annotations.begin(); | ||
| 43 | + iter != this->m->field_to_annotations.end(); ++iter) | ||
| 44 | + { | ||
| 45 | + result.push_back(this->qpdf.getObjectByObjGen((*iter).first)); | ||
| 46 | + } | ||
| 47 | + return result; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +std::vector<QPDFAnnotationObjectHelper> | ||
| 51 | +QPDFAcroFormDocumentHelper::getAnnotationsForField(QPDFFormFieldObjectHelper h) | ||
| 52 | +{ | ||
| 53 | + analyze(); | ||
| 54 | + std::vector<QPDFAnnotationObjectHelper> result; | ||
| 55 | + QPDFObjGen og(h.getObjectHandle().getObjGen()); | ||
| 56 | + if (this->m->field_to_annotations.count(og)) | ||
| 57 | + { | ||
| 58 | + result = this->m->field_to_annotations[og]; | ||
| 59 | + } | ||
| 60 | + return result; | ||
| 61 | +} | ||
| 62 | + | ||
| 63 | +std::vector<QPDFAnnotationObjectHelper> | ||
| 64 | +QPDFAcroFormDocumentHelper::getWidgetAnnotationsForPage(QPDFPageObjectHelper h) | ||
| 65 | +{ | ||
| 66 | + return h.getAnnotations("/Widget"); | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +QPDFFormFieldObjectHelper | ||
| 70 | +QPDFAcroFormDocumentHelper::getFieldForAnnotation(QPDFAnnotationObjectHelper h) | ||
| 71 | +{ | ||
| 72 | + QPDFObjectHandle oh = h.getObjectHandle(); | ||
| 73 | + if (! (oh.isDictionary() && | ||
| 74 | + oh.getKey("/Subtype").isName() && | ||
| 75 | + (oh.getKey("/Subtype").getName() == "/Widget"))) | ||
| 76 | + { | ||
| 77 | + throw std::logic_error( | ||
| 78 | + "QPDFAnnotationObjectHelper::getFieldForAnnotation called for" | ||
| 79 | + " non-/Widget annotation"); | ||
| 80 | + } | ||
| 81 | + analyze(); | ||
| 82 | + QPDFFormFieldObjectHelper result(QPDFObjectHandle::newNull()); | ||
| 83 | + QPDFObjGen og(oh.getObjGen()); | ||
| 84 | + if (this->m->annotation_to_field.count(og)) | ||
| 85 | + { | ||
| 86 | + result = this->m->annotation_to_field[og]; | ||
| 87 | + } | ||
| 88 | + return result; | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +void | ||
| 92 | +QPDFAcroFormDocumentHelper::analyze() | ||
| 93 | +{ | ||
| 94 | + if (this->m->cache_valid) | ||
| 95 | + { | ||
| 96 | + return; | ||
| 97 | + } | ||
| 98 | + this->m->cache_valid = true; | ||
| 99 | + QPDFObjectHandle acroform = this->qpdf.getRoot().getKey("/AcroForm"); | ||
| 100 | + if (! (acroform.isDictionary() && acroform.hasKey("/Fields"))) | ||
| 101 | + { | ||
| 102 | + return; | ||
| 103 | + } | ||
| 104 | + QPDFObjectHandle fields = acroform.getKey("/Fields"); | ||
| 105 | + if (! fields.isArray()) | ||
| 106 | + { | ||
| 107 | + QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array"); | ||
| 108 | + acroform.warnIfPossible( | ||
| 109 | + "/Fields key of /AcroForm dictionary is not an array; ignoring"); | ||
| 110 | + fields = QPDFObjectHandle::newArray(); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + // Traverse /AcroForm to find annotations and map them | ||
| 114 | + // bidirectionally to fields. | ||
| 115 | + | ||
| 116 | + std::set<QPDFObjGen> visited; | ||
| 117 | + size_t nfields = fields.getArrayNItems(); | ||
| 118 | + QPDFObjectHandle null(QPDFObjectHandle::newNull()); | ||
| 119 | + for (size_t i = 0; i < nfields; ++i) | ||
| 120 | + { | ||
| 121 | + traverseField(fields.getArrayItem(i), null, 0, visited); | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + // All Widget annotations should have been encountered by | ||
| 125 | + // traversing /AcroForm, but in case any weren't, find them by | ||
| 126 | + // walking through pages, and treat any widget annotation that is | ||
| 127 | + // not associated with a field as its own field. This just ensures | ||
| 128 | + // that requesting the field for any annotation we find through a | ||
| 129 | + // page's /Annots list will have some associated field. Note that | ||
| 130 | + // a file that contains this kind of error will probably not | ||
| 131 | + // actually work with most viewers. | ||
| 132 | + | ||
| 133 | + QPDFPageDocumentHelper dh(this->qpdf); | ||
| 134 | + std::vector<QPDFPageObjectHelper> pages = dh.getAllPages(); | ||
| 135 | + for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin(); | ||
| 136 | + iter != pages.end(); ++iter) | ||
| 137 | + { | ||
| 138 | + QPDFPageObjectHelper ph(*iter); | ||
| 139 | + std::vector<QPDFAnnotationObjectHelper> annots = | ||
| 140 | + getWidgetAnnotationsForPage(ph); | ||
| 141 | + for (std::vector<QPDFAnnotationObjectHelper>::iterator i2 = | ||
| 142 | + annots.begin(); | ||
| 143 | + i2 != annots.end(); ++i2) | ||
| 144 | + { | ||
| 145 | + QPDFObjectHandle annot((*i2).getObjectHandle()); | ||
| 146 | + QPDFObjGen og(annot.getObjGen()); | ||
| 147 | + if (this->m->annotation_to_field.count(og) == 0) | ||
| 148 | + { | ||
| 149 | + QTC::TC("qpdf", "QPDFAcroFormDocumentHelper orphaned widget"); | ||
| 150 | + // This is not supposed to happen, but it's easy | ||
| 151 | + // enough for us to handle this case. Treat the | ||
| 152 | + // annotation as its own field. This could allow qpdf | ||
| 153 | + // to sensibly handle a case such as a PDF creator | ||
| 154 | + // adding a self-contained annotation (merged with the | ||
| 155 | + // field dictionary) to the page's /Annots array and | ||
| 156 | + // forgetting to also put it in /AcroForm. | ||
| 157 | + annot.warnIfPossible( | ||
| 158 | + "this widget annotation is not" | ||
| 159 | + " reachable from /AcroForm in the document catalog"); | ||
| 160 | + this->m->annotation_to_field[og] = | ||
| 161 | + QPDFFormFieldObjectHelper(annot); | ||
| 162 | + this->m->field_to_annotations[og].push_back( | ||
| 163 | + QPDFAnnotationObjectHelper(annot)); | ||
| 164 | + } | ||
| 165 | + } | ||
| 166 | + } | ||
| 167 | +} | ||
| 168 | + | ||
| 169 | +void | ||
| 170 | +QPDFAcroFormDocumentHelper::traverseField( | ||
| 171 | + QPDFObjectHandle field, QPDFObjectHandle parent, int depth, | ||
| 172 | + std::set<QPDFObjGen>& visited) | ||
| 173 | +{ | ||
| 174 | + if (depth > 100) | ||
| 175 | + { | ||
| 176 | + // Arbitrarily cut off recursion at a fixed depth to avoid | ||
| 177 | + // specially crafted files that could cause stack overflow. | ||
| 178 | + return; | ||
| 179 | + } | ||
| 180 | + if (! field.isIndirect()) | ||
| 181 | + { | ||
| 182 | + QTC::TC("qpdf", "QPDFAcroFormDocumentHelper direct field"); | ||
| 183 | + field.warnIfPossible( | ||
| 184 | + "encountered a direct object as a field or annotation while" | ||
| 185 | + " traversing /AcroForm; ignoring field or annotation"); | ||
| 186 | + return; | ||
| 187 | + } | ||
| 188 | + if (! field.isDictionary()) | ||
| 189 | + { | ||
| 190 | + QTC::TC("qpdf", "QPDFAcroFormDocumentHelper non-dictionary field"); | ||
| 191 | + field.warnIfPossible( | ||
| 192 | + "encountered a non-dictionary as a field or annotation while" | ||
| 193 | + " traversing /AcroForm; ignoring field or annotation"); | ||
| 194 | + return; | ||
| 195 | + } | ||
| 196 | + QPDFObjGen og(field.getObjGen()); | ||
| 197 | + if (visited.count(og) != 0) | ||
| 198 | + { | ||
| 199 | + QTC::TC("qpdf", "QPDFAcroFormDocumentHelper loop"); | ||
| 200 | + field.warnIfPossible("loop detected while traversing /AcroForm"); | ||
| 201 | + return; | ||
| 202 | + } | ||
| 203 | + visited.insert(og); | ||
| 204 | + | ||
| 205 | + // A dictionary encountered while traversing the /AcroForm field | ||
| 206 | + // may be a form field, an annotation, or the merger of the two. A | ||
| 207 | + // field that has no fields below it is a terminal. If a terminal | ||
| 208 | + // field looks like an annotation, it is an annotation because | ||
| 209 | + // annotation dictionary fields can be merged with terminal field | ||
| 210 | + // dictionaries. Otherwise, the annotation fields might be there | ||
| 211 | + // to be inherited by annotations below it. | ||
| 212 | + | ||
| 213 | + bool is_annotation = false; | ||
| 214 | + bool is_field = (0 == depth); | ||
| 215 | + QPDFObjectHandle kids = field.getKey("/Kids"); | ||
| 216 | + if (kids.isArray()) | ||
| 217 | + { | ||
| 218 | + is_field = true; | ||
| 219 | + size_t nkids = kids.getArrayNItems(); | ||
| 220 | + for (size_t k = 0; k < nkids; ++k) | ||
| 221 | + { | ||
| 222 | + traverseField(kids.getArrayItem(k), field, 1 + depth, visited); | ||
| 223 | + } | ||
| 224 | + } | ||
| 225 | + else | ||
| 226 | + { | ||
| 227 | + if (field.hasKey("/Parent")) | ||
| 228 | + { | ||
| 229 | + is_field = true; | ||
| 230 | + } | ||
| 231 | + if (field.hasKey("/Subtype") || | ||
| 232 | + field.hasKey("/Rect") || | ||
| 233 | + field.hasKey("/AP")) | ||
| 234 | + { | ||
| 235 | + is_annotation = true; | ||
| 236 | + } | ||
| 237 | + } | ||
| 238 | + | ||
| 239 | + QTC::TC("qpdf", "QPDFAcroFormDocumentHelper field found", | ||
| 240 | + (depth == 0) ? 0 : 1); | ||
| 241 | + QTC::TC("qpdf", "QPDFAcroFormDocumentHelper annotation found", | ||
| 242 | + (is_field ? 0 : 1)); | ||
| 243 | + | ||
| 244 | + if (is_annotation) | ||
| 245 | + { | ||
| 246 | + QPDFObjectHandle our_field = (is_field ? field : parent); | ||
| 247 | + this->m->field_to_annotations[our_field.getObjGen()].push_back( | ||
| 248 | + QPDFAnnotationObjectHelper(field)); | ||
| 249 | + this->m->annotation_to_field[og] = | ||
| 250 | + QPDFFormFieldObjectHelper(our_field); | ||
| 251 | + } | ||
| 252 | +} |
libqpdf/QPDFAnnotationObjectHelper.cc
0 → 100644
| 1 | +#include <qpdf/QPDFAnnotationObjectHelper.hh> | ||
| 2 | +#include <qpdf/QTC.hh> | ||
| 3 | + | ||
| 4 | +QPDFAnnotationObjectHelper::Members::~Members() | ||
| 5 | +{ | ||
| 6 | +} | ||
| 7 | + | ||
| 8 | +QPDFAnnotationObjectHelper::Members::Members() | ||
| 9 | +{ | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +QPDFAnnotationObjectHelper::QPDFAnnotationObjectHelper(QPDFObjectHandle oh) : | ||
| 13 | + QPDFObjectHelper(oh) | ||
| 14 | +{ | ||
| 15 | +} | ||
| 16 | + | ||
| 17 | +std::string | ||
| 18 | +QPDFAnnotationObjectHelper::getSubtype() | ||
| 19 | +{ | ||
| 20 | + return this->oh.getKey("/Subtype").getName(); | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +QPDFObjectHandle::Rectangle | ||
| 24 | +QPDFAnnotationObjectHelper::getRect() | ||
| 25 | +{ | ||
| 26 | + return this->oh.getKey("/Rect").getArrayAsRectangle(); | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +QPDFObjectHandle | ||
| 30 | +QPDFAnnotationObjectHelper::getAppearanceDictionary() | ||
| 31 | +{ | ||
| 32 | + return this->oh.getKey("/AP"); | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +std::string | ||
| 36 | +QPDFAnnotationObjectHelper::getAppearanceState() | ||
| 37 | +{ | ||
| 38 | + if (this->oh.getKey("/AS").isName()) | ||
| 39 | + { | ||
| 40 | + QTC::TC("qpdf", "QPDFAnnotationObjectHelper AS present"); | ||
| 41 | + return this->oh.getKey("/AS").getName(); | ||
| 42 | + } | ||
| 43 | + QTC::TC("qpdf", "QPDFAnnotationObjectHelper AS absent"); | ||
| 44 | + return ""; | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +QPDFObjectHandle | ||
| 48 | +QPDFAnnotationObjectHelper::getAppearanceStream( | ||
| 49 | + std::string const& which, | ||
| 50 | + std::string const& state) | ||
| 51 | +{ | ||
| 52 | + QPDFObjectHandle ap = getAppearanceDictionary(); | ||
| 53 | + std::string desired_state = state.empty() ? getAppearanceState() : state; | ||
| 54 | + if (ap.isDictionary()) | ||
| 55 | + { | ||
| 56 | + QPDFObjectHandle ap_sub = ap.getKey(which); | ||
| 57 | + if (ap_sub.isStream() && desired_state.empty()) | ||
| 58 | + { | ||
| 59 | + QTC::TC("qpdf", "QPDFAnnotationObjectHelper AP stream"); | ||
| 60 | + return ap_sub; | ||
| 61 | + } | ||
| 62 | + if (ap_sub.isDictionary() && (! desired_state.empty())) | ||
| 63 | + { | ||
| 64 | + QTC::TC("qpdf", "QPDFAnnotationObjectHelper AP dictionary"); | ||
| 65 | + QPDFObjectHandle ap_sub_val = ap_sub.getKey(desired_state); | ||
| 66 | + if (ap_sub_val.isStream()) | ||
| 67 | + { | ||
| 68 | + QTC::TC("qpdf", "QPDFAnnotationObjectHelper AN sub stream"); | ||
| 69 | + return ap_sub_val; | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + QTC::TC("qpdf", "QPDFAnnotationObjectHelper AN null"); | ||
| 74 | + return QPDFObjectHandle::newNull(); | ||
| 75 | +} |
libqpdf/QPDFFormFieldObjectHelper.cc
0 → 100644
| 1 | +#include <qpdf/QPDFFormFieldObjectHelper.hh> | ||
| 2 | +#include <qpdf/QTC.hh> | ||
| 3 | + | ||
| 4 | +QPDFFormFieldObjectHelper::Members::~Members() | ||
| 5 | +{ | ||
| 6 | +} | ||
| 7 | + | ||
| 8 | +QPDFFormFieldObjectHelper::Members::Members() | ||
| 9 | +{ | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper(QPDFObjectHandle oh) : | ||
| 13 | + QPDFObjectHelper(oh), | ||
| 14 | + m(new Members()) | ||
| 15 | +{ | ||
| 16 | +} | ||
| 17 | + | ||
| 18 | +QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper() : | ||
| 19 | + QPDFObjectHelper(QPDFObjectHandle::newNull()), | ||
| 20 | + m(new Members()) | ||
| 21 | +{ | ||
| 22 | +} | ||
| 23 | + | ||
| 24 | +bool | ||
| 25 | +QPDFFormFieldObjectHelper::isNull() | ||
| 26 | +{ | ||
| 27 | + return this->oh.isNull(); | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +QPDFFormFieldObjectHelper | ||
| 31 | +QPDFFormFieldObjectHelper::getParent() | ||
| 32 | +{ | ||
| 33 | + return this->oh.getKey("/Parent"); // may be null | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +QPDFObjectHandle | ||
| 37 | +QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name) | ||
| 38 | +{ | ||
| 39 | + QPDFObjectHandle node = this->oh; | ||
| 40 | + QPDFObjectHandle result(node.getKey(name)); | ||
| 41 | + std::set<QPDFObjGen> seen; | ||
| 42 | + while (result.isNull() && node.hasKey("/Parent")) | ||
| 43 | + { | ||
| 44 | + seen.insert(node.getObjGen()); | ||
| 45 | + node = node.getKey("/Parent"); | ||
| 46 | + if (seen.count(node.getObjGen())) | ||
| 47 | + { | ||
| 48 | + break; | ||
| 49 | + } | ||
| 50 | + result = node.getKey(name); | ||
| 51 | + if (! result.isNull()) | ||
| 52 | + { | ||
| 53 | + QTC::TC("qpdf", "QPDFFormFieldObjectHelper non-trivial inheritance"); | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | + return result; | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +std::string | ||
| 60 | +QPDFFormFieldObjectHelper::getInheritableFieldValueAsString( | ||
| 61 | + std::string const& name) | ||
| 62 | +{ | ||
| 63 | + QPDFObjectHandle fv = getInheritableFieldValue(name); | ||
| 64 | + std::string result; | ||
| 65 | + if (fv.isString()) | ||
| 66 | + { | ||
| 67 | + result = fv.getUTF8Value(); | ||
| 68 | + } | ||
| 69 | + return result; | ||
| 70 | +} | ||
| 71 | + | ||
| 72 | +std::string | ||
| 73 | +QPDFFormFieldObjectHelper::getInheritableFieldValueAsName( | ||
| 74 | + std::string const& name) | ||
| 75 | +{ | ||
| 76 | + QPDFObjectHandle fv = getInheritableFieldValue(name); | ||
| 77 | + std::string result; | ||
| 78 | + if (fv.isName()) | ||
| 79 | + { | ||
| 80 | + result = fv.getName(); | ||
| 81 | + } | ||
| 82 | + return result; | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +std::string | ||
| 86 | +QPDFFormFieldObjectHelper::getFieldType() | ||
| 87 | +{ | ||
| 88 | + return getInheritableFieldValueAsName("/FT"); | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +std::string | ||
| 92 | +QPDFFormFieldObjectHelper::getFullyQualifiedName() | ||
| 93 | +{ | ||
| 94 | + std::string result; | ||
| 95 | + QPDFObjectHandle node = this->oh; | ||
| 96 | + std::set<QPDFObjGen> seen; | ||
| 97 | + while ((! node.isNull()) && (seen.count(node.getObjGen()) == 0)) | ||
| 98 | + { | ||
| 99 | + if (node.getKey("/T").isString()) | ||
| 100 | + { | ||
| 101 | + if (! result.empty()) | ||
| 102 | + { | ||
| 103 | + QTC::TC("qpdf", "QPDFFormFieldObjectHelper non-trivial qualified name"); | ||
| 104 | + result = "." + result; | ||
| 105 | + } | ||
| 106 | + result = node.getKey("/T").getUTF8Value() + result; | ||
| 107 | + } | ||
| 108 | + seen.insert(node.getObjGen()); | ||
| 109 | + node = node.getKey("/Parent"); | ||
| 110 | + } | ||
| 111 | + return result; | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +std::string | ||
| 115 | +QPDFFormFieldObjectHelper::getPartialName() | ||
| 116 | +{ | ||
| 117 | + std::string result; | ||
| 118 | + if (this->oh.getKey("/T").isString()) | ||
| 119 | + { | ||
| 120 | + result = this->oh.getKey("/T").getUTF8Value(); | ||
| 121 | + } | ||
| 122 | + return result; | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | +std::string | ||
| 126 | +QPDFFormFieldObjectHelper::getAlternativeName() | ||
| 127 | +{ | ||
| 128 | + if (this->oh.getKey("/TU").isString()) | ||
| 129 | + { | ||
| 130 | + QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU present"); | ||
| 131 | + return this->oh.getKey("/TU").getUTF8Value(); | ||
| 132 | + } | ||
| 133 | + QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU absent"); | ||
| 134 | + return getFullyQualifiedName(); | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +std::string | ||
| 138 | +QPDFFormFieldObjectHelper::getMappingName() | ||
| 139 | +{ | ||
| 140 | + if (this->oh.getKey("/TM").isString()) | ||
| 141 | + { | ||
| 142 | + QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM present"); | ||
| 143 | + return this->oh.getKey("/TM").getUTF8Value(); | ||
| 144 | + } | ||
| 145 | + QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM absent"); | ||
| 146 | + return getAlternativeName(); | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | +QPDFObjectHandle | ||
| 150 | +QPDFFormFieldObjectHelper::getValue() | ||
| 151 | +{ | ||
| 152 | + return getInheritableFieldValue("/V"); | ||
| 153 | +} | ||
| 154 | + | ||
| 155 | +std::string | ||
| 156 | +QPDFFormFieldObjectHelper::getValueAsString() | ||
| 157 | +{ | ||
| 158 | + return getInheritableFieldValueAsString("/V"); | ||
| 159 | +} | ||
| 160 | + | ||
| 161 | +QPDFObjectHandle | ||
| 162 | +QPDFFormFieldObjectHelper::getDefaultValue() | ||
| 163 | +{ | ||
| 164 | + return getInheritableFieldValue("/DV"); | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | +std::string | ||
| 168 | +QPDFFormFieldObjectHelper::getDefaultValueAsString() | ||
| 169 | +{ | ||
| 170 | + return getInheritableFieldValueAsString("/DV"); | ||
| 171 | +} | ||
| 172 | + | ||
| 173 | +std::string | ||
| 174 | +QPDFFormFieldObjectHelper::getDefaultAppearance() | ||
| 175 | +{ | ||
| 176 | + return getInheritableFieldValueAsString("/DA"); | ||
| 177 | +} | ||
| 178 | + | ||
| 179 | +int | ||
| 180 | +QPDFFormFieldObjectHelper::getQuadding() | ||
| 181 | +{ | ||
| 182 | + int result = 0; | ||
| 183 | + QPDFObjectHandle fv = getInheritableFieldValue("/Q"); | ||
| 184 | + if (fv.isInteger()) | ||
| 185 | + { | ||
| 186 | + QTC::TC("qpdf", "QPDFFormFieldObjectHelper Q present"); | ||
| 187 | + result = static_cast<int>(fv.getIntValue()); | ||
| 188 | + } | ||
| 189 | + return result; | ||
| 190 | +} |
libqpdf/QPDFPageObjectHelper.cc
| @@ -19,6 +19,29 @@ QPDFPageObjectHelper::getPageImages() | @@ -19,6 +19,29 @@ QPDFPageObjectHelper::getPageImages() | ||
| 19 | return this->oh.getPageImages(); | 19 | return this->oh.getPageImages(); |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | +std::vector<QPDFAnnotationObjectHelper> | ||
| 23 | +QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) | ||
| 24 | +{ | ||
| 25 | + std::vector<QPDFAnnotationObjectHelper> result; | ||
| 26 | + QPDFObjectHandle annots = this->oh.getKey("/Annots"); | ||
| 27 | + if (annots.isArray()) | ||
| 28 | + { | ||
| 29 | + size_t nannots = annots.getArrayNItems(); | ||
| 30 | + for (size_t i = 0; i < nannots; ++i) | ||
| 31 | + { | ||
| 32 | + QPDFObjectHandle annot = annots.getArrayItem(i); | ||
| 33 | + if (only_subtype.empty() || | ||
| 34 | + (annot.isDictionary() && | ||
| 35 | + annot.getKey("/Subtype").isName() && | ||
| 36 | + (only_subtype == annot.getKey("/Subtype").getName()))) | ||
| 37 | + { | ||
| 38 | + result.push_back(QPDFAnnotationObjectHelper(annot)); | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | + return result; | ||
| 43 | +} | ||
| 44 | + | ||
| 22 | std::vector<QPDFObjectHandle> | 45 | std::vector<QPDFObjectHandle> |
| 23 | QPDFPageObjectHelper::getPageContents() | 46 | QPDFPageObjectHelper::getPageContents() |
| 24 | { | 47 | { |
libqpdf/build.mk
| @@ -35,7 +35,10 @@ SRCS_libqpdf = \ | @@ -35,7 +35,10 @@ SRCS_libqpdf = \ | ||
| 35 | libqpdf/Pl_StdioFile.cc \ | 35 | libqpdf/Pl_StdioFile.cc \ |
| 36 | libqpdf/Pl_TIFFPredictor.cc \ | 36 | libqpdf/Pl_TIFFPredictor.cc \ |
| 37 | libqpdf/QPDF.cc \ | 37 | libqpdf/QPDF.cc \ |
| 38 | + libqpdf/QPDFAcroFormDocumentHelper.cc \ | ||
| 39 | + libqpdf/QPDFAnnotationObjectHelper.cc \ | ||
| 38 | libqpdf/QPDFExc.cc \ | 40 | libqpdf/QPDFExc.cc \ |
| 41 | + libqpdf/QPDFFormFieldObjectHelper.cc \ | ||
| 39 | libqpdf/QPDFObjGen.cc \ | 42 | libqpdf/QPDFObjGen.cc \ |
| 40 | libqpdf/QPDFObject.cc \ | 43 | libqpdf/QPDFObject.cc \ |
| 41 | libqpdf/QPDFObjectHandle.cc \ | 44 | libqpdf/QPDFObjectHandle.cc \ |
qpdf/qpdf.testcov
| @@ -336,3 +336,23 @@ QPDFObjectHandle erase array bounds 0 | @@ -336,3 +336,23 @@ QPDFObjectHandle erase array bounds 0 | ||
| 336 | qpdf-c called qpdf_check_pdf 0 | 336 | qpdf-c called qpdf_check_pdf 0 |
| 337 | QPDF xref loop 0 | 337 | QPDF xref loop 0 |
| 338 | QPDFObjectHandle too deep 0 | 338 | QPDFObjectHandle too deep 0 |
| 339 | +QPDFFormFieldObjectHelper non-trivial inheritance 0 | ||
| 340 | +QPDFFormFieldObjectHelper non-trivial qualified name 0 | ||
| 341 | +QPDFFormFieldObjectHelper TU present 0 | ||
| 342 | +QPDFFormFieldObjectHelper TM present 0 | ||
| 343 | +QPDFFormFieldObjectHelper TU absent 0 | ||
| 344 | +QPDFFormFieldObjectHelper TM absent 0 | ||
| 345 | +QPDFFormFieldObjectHelper Q present 0 | ||
| 346 | +QPDFAnnotationObjectHelper AS present 0 | ||
| 347 | +QPDFAnnotationObjectHelper AS absent 0 | ||
| 348 | +QPDFAnnotationObjectHelper AP stream 0 | ||
| 349 | +QPDFAnnotationObjectHelper AP dictionary 0 | ||
| 350 | +QPDFAnnotationObjectHelper AN sub stream 0 | ||
| 351 | +QPDFAnnotationObjectHelper AN null 0 | ||
| 352 | +QPDFAcroFormDocumentHelper fields not array 0 | ||
| 353 | +QPDFAcroFormDocumentHelper orphaned widget 0 | ||
| 354 | +QPDFAcroFormDocumentHelper direct field 0 | ||
| 355 | +QPDFAcroFormDocumentHelper non-dictionary field 0 | ||
| 356 | +QPDFAcroFormDocumentHelper loop 0 | ||
| 357 | +QPDFAcroFormDocumentHelper field found 1 | ||
| 358 | +QPDFAcroFormDocumentHelper annotation found 1 |
qpdf/qtest/qpdf.test
| @@ -94,6 +94,38 @@ $td->runtest("PDF doc encoding to Unicode", | @@ -94,6 +94,38 @@ $td->runtest("PDF doc encoding to Unicode", | ||
| 94 | 94 | ||
| 95 | show_ntests(); | 95 | show_ntests(); |
| 96 | # ---------- | 96 | # ---------- |
| 97 | +$td->notify("--- Form Tests ---"); | ||
| 98 | + | ||
| 99 | +my @form_tests = ( | ||
| 100 | + 'minimal', | ||
| 101 | + 'form-empty-from-odt', | ||
| 102 | + 'form-mod1', | ||
| 103 | + # Atril (MATE Document Viewer) 1.20.1 dumps appearance streams | ||
| 104 | + # when modifying form fields, leaving /NeedAppearances true. | ||
| 105 | + 'form-filled-with-atril', | ||
| 106 | + 'form-bad-fields-array', | ||
| 107 | + 'form-errors', | ||
| 108 | + ); | ||
| 109 | + | ||
| 110 | +$n_tests += scalar(@form_tests); | ||
| 111 | + | ||
| 112 | +# Many of the form*.pdf files were created by converting the | ||
| 113 | +# LibreOffice document storage/form.odt to PDF and then manually | ||
| 114 | +# modifying the resulting PDF in various ways. That file would be good | ||
| 115 | +# starting point for generation of more complex forms should that be | ||
| 116 | +# required in the future. The file storage/form.pdf is a direct export | ||
| 117 | +# from LibreOffice with no modifications. | ||
| 118 | + | ||
| 119 | +foreach my $f (@form_tests) | ||
| 120 | +{ | ||
| 121 | + $td->runtest("form test: $f", | ||
| 122 | + {$td->COMMAND => "test_driver 43 $f.pdf"}, | ||
| 123 | + {$td->FILE => "form-$f.out", $td->EXIT_STATUS => 0}, | ||
| 124 | + $td->NORMALIZE_NEWLINES); | ||
| 125 | +} | ||
| 126 | + | ||
| 127 | +show_ntests(); | ||
| 128 | +# ---------- | ||
| 97 | $td->notify("--- Stream Replacement Tests ---"); | 129 | $td->notify("--- Stream Replacement Tests ---"); |
| 98 | $n_tests += 8; | 130 | $n_tests += 8; |
| 99 | 131 |
qpdf/qtest/qpdf/form-bad-fields-array.pdf
0 → 100644
No preview for this file type
qpdf/qtest/qpdf/form-empty-from-odt.pdf
0 → 100644
No preview for this file type
qpdf/qtest/qpdf/form-errors.pdf
0 → 100644
No preview for this file type
qpdf/qtest/qpdf/form-filled-with-atril.pdf
0 → 100644
No preview for this file type
qpdf/qtest/qpdf/form-form-bad-fields-array.out
0 → 100644
| 1 | +iterating over form fields | ||
| 2 | +WARNING: form-bad-fields-array.pdf, object 1 0 at offset 50: /Fields key of /AcroForm dictionary is not an array; ignoring | ||
| 3 | +WARNING: form-bad-fields-array.pdf, object 4 0 at offset 615: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 4 | +WARNING: form-bad-fields-array.pdf, object 16 0 at offset 3419: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 5 | +WARNING: form-bad-fields-array.pdf, object 17 0 at offset 3775: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 6 | +WARNING: form-bad-fields-array.pdf, object 18 0 at offset 4131: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 7 | +WARNING: form-bad-fields-array.pdf, object 6 0 at offset 1032: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 8 | +WARNING: form-bad-fields-array.pdf, object 7 0 at offset 1413: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 9 | +WARNING: form-bad-fields-array.pdf, object 8 0 at offset 1796: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 10 | +WARNING: form-bad-fields-array.pdf, object 32 0 at offset 5893: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 11 | +WARNING: form-bad-fields-array.pdf, object 33 0 at offset 6251: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 12 | +WARNING: form-bad-fields-array.pdf, object 34 0 at offset 6607: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 13 | +WARNING: form-bad-fields-array.pdf, object 10 0 at offset 2311: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 14 | +Field: 4 0 R | ||
| 15 | + Parent: none | ||
| 16 | + Fully qualified name: Text Box 1 | ||
| 17 | + Partial name: Text Box 1 | ||
| 18 | + Alternative name: Text Box 1 | ||
| 19 | + Mapping name: Text Box 1 | ||
| 20 | + Field type: /Tx | ||
| 21 | + Value: <feff> | ||
| 22 | + Value as string: | ||
| 23 | + Default value: <feff> | ||
| 24 | + Default value as string: | ||
| 25 | + Default appearance: 0.18039 0.20392 0.21176 rg /F2 12 Tf | ||
| 26 | + Quadding: 0 | ||
| 27 | + Annotation: 4 0 R | ||
| 28 | +Field: 6 0 R | ||
| 29 | + Parent: none | ||
| 30 | + Fully qualified name: Check Box 1 | ||
| 31 | + Partial name: Check Box 1 | ||
| 32 | + Alternative name: Check Box 1 | ||
| 33 | + Mapping name: Check Box 1 | ||
| 34 | + Field type: /Btn | ||
| 35 | + Value: /Off | ||
| 36 | + Value as string: | ||
| 37 | + Default value: /Off | ||
| 38 | + Default value as string: | ||
| 39 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 40 | + Quadding: 0 | ||
| 41 | + Annotation: 6 0 R | ||
| 42 | +Field: 7 0 R | ||
| 43 | + Parent: none | ||
| 44 | + Fully qualified name: Check Box 2 | ||
| 45 | + Partial name: Check Box 2 | ||
| 46 | + Alternative name: Check Box 2 | ||
| 47 | + Mapping name: Check Box 2 | ||
| 48 | + Field type: /Btn | ||
| 49 | + Value: /Yes | ||
| 50 | + Value as string: | ||
| 51 | + Default value: /Yes | ||
| 52 | + Default value as string: | ||
| 53 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 54 | + Quadding: 0 | ||
| 55 | + Annotation: 7 0 R | ||
| 56 | +Field: 8 0 R | ||
| 57 | + Parent: none | ||
| 58 | + Fully qualified name: Check Box 3 | ||
| 59 | + Partial name: Check Box 3 | ||
| 60 | + Alternative name: Check Box 3 | ||
| 61 | + Mapping name: Check Box 3 | ||
| 62 | + Field type: /Btn | ||
| 63 | + Value: /Off | ||
| 64 | + Value as string: | ||
| 65 | + Default value: /Off | ||
| 66 | + Default value as string: | ||
| 67 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 68 | + Quadding: 0 | ||
| 69 | + Annotation: 8 0 R | ||
| 70 | +Field: 10 0 R | ||
| 71 | + Parent: none | ||
| 72 | + Fully qualified name: Text Box 2 | ||
| 73 | + Partial name: Text Box 2 | ||
| 74 | + Alternative name: Text Box 2 | ||
| 75 | + Mapping name: Text Box 2 | ||
| 76 | + Field type: /Tx | ||
| 77 | + Value: <feff00730061006c00610064002003c002ac> | ||
| 78 | + Value as string: salad πʬ | ||
| 79 | + Default value: <feff00730061006c00610064002003c002ac> | ||
| 80 | + Default value as string: salad πʬ | ||
| 81 | + Default appearance: 0.18039 0.20392 0.21176 rg /F2 12 Tf | ||
| 82 | + Quadding: 0 | ||
| 83 | + Annotation: 10 0 R | ||
| 84 | +Field: 16 0 R | ||
| 85 | + Parent: 5 0 R | ||
| 86 | + Parent: none | ||
| 87 | + Fully qualified name: r1 | ||
| 88 | + Partial name: | ||
| 89 | + Alternative name: r1 | ||
| 90 | + Mapping name: r1 | ||
| 91 | + Field type: /Btn | ||
| 92 | + Value: /1 | ||
| 93 | + Value as string: | ||
| 94 | + Default value: /1 | ||
| 95 | + Default value as string: | ||
| 96 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 97 | + Quadding: 0 | ||
| 98 | + Annotation: 16 0 R | ||
| 99 | +Field: 17 0 R | ||
| 100 | + Parent: 5 0 R | ||
| 101 | + Parent: none | ||
| 102 | + Fully qualified name: r1 | ||
| 103 | + Partial name: | ||
| 104 | + Alternative name: r1 | ||
| 105 | + Mapping name: r1 | ||
| 106 | + Field type: /Btn | ||
| 107 | + Value: /1 | ||
| 108 | + Value as string: | ||
| 109 | + Default value: /1 | ||
| 110 | + Default value as string: | ||
| 111 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 112 | + Quadding: 0 | ||
| 113 | + Annotation: 17 0 R | ||
| 114 | +Field: 18 0 R | ||
| 115 | + Parent: 5 0 R | ||
| 116 | + Parent: none | ||
| 117 | + Fully qualified name: r1 | ||
| 118 | + Partial name: | ||
| 119 | + Alternative name: r1 | ||
| 120 | + Mapping name: r1 | ||
| 121 | + Field type: /Btn | ||
| 122 | + Value: /1 | ||
| 123 | + Value as string: | ||
| 124 | + Default value: /1 | ||
| 125 | + Default value as string: | ||
| 126 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 127 | + Quadding: 0 | ||
| 128 | + Annotation: 18 0 R | ||
| 129 | +Field: 32 0 R | ||
| 130 | + Parent: 9 0 R | ||
| 131 | + Parent: none | ||
| 132 | + Fully qualified name: r2 | ||
| 133 | + Partial name: | ||
| 134 | + Alternative name: r2 | ||
| 135 | + Mapping name: r2 | ||
| 136 | + Field type: /Btn | ||
| 137 | + Value: /2 | ||
| 138 | + Value as string: | ||
| 139 | + Default value: /2 | ||
| 140 | + Default value as string: | ||
| 141 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 142 | + Quadding: 0 | ||
| 143 | + Annotation: 32 0 R | ||
| 144 | +Field: 33 0 R | ||
| 145 | + Parent: 9 0 R | ||
| 146 | + Parent: none | ||
| 147 | + Fully qualified name: r2 | ||
| 148 | + Partial name: | ||
| 149 | + Alternative name: r2 | ||
| 150 | + Mapping name: r2 | ||
| 151 | + Field type: /Btn | ||
| 152 | + Value: /2 | ||
| 153 | + Value as string: | ||
| 154 | + Default value: /2 | ||
| 155 | + Default value as string: | ||
| 156 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 157 | + Quadding: 0 | ||
| 158 | + Annotation: 33 0 R | ||
| 159 | +Field: 34 0 R | ||
| 160 | + Parent: 9 0 R | ||
| 161 | + Parent: none | ||
| 162 | + Fully qualified name: r2 | ||
| 163 | + Partial name: | ||
| 164 | + Alternative name: r2 | ||
| 165 | + Mapping name: r2 | ||
| 166 | + Field type: /Btn | ||
| 167 | + Value: /2 | ||
| 168 | + Value as string: | ||
| 169 | + Default value: /2 | ||
| 170 | + Default value as string: | ||
| 171 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 172 | + Quadding: 0 | ||
| 173 | + Annotation: 34 0 R | ||
| 174 | +iterating over annotations per page | ||
| 175 | +Page: 11 0 R | ||
| 176 | + Annotation: 4 0 R | ||
| 177 | + Field: 4 0 R | ||
| 178 | + Subtype: /Widget | ||
| 179 | + Rect: [123.4, 692.1, 260.9, 706.7] | ||
| 180 | + Appearance stream (/N): 14 0 R | ||
| 181 | + Appearance stream (/N, /3): null | ||
| 182 | + Annotation: 16 0 R | ||
| 183 | + Field: 16 0 R | ||
| 184 | + Subtype: /Widget | ||
| 185 | + Rect: [149.3, 648.5, 161.6, 660.4] | ||
| 186 | + Appearance state: /1 | ||
| 187 | + Appearance stream (/N): 44 0 R | ||
| 188 | + Appearance stream (/N, /3): null | ||
| 189 | + Annotation: 17 0 R | ||
| 190 | + Field: 17 0 R | ||
| 191 | + Subtype: /Widget | ||
| 192 | + Rect: [152.7, 627.3, 165, 639.2] | ||
| 193 | + Appearance state: /Off | ||
| 194 | + Appearance stream (/N): 50 0 R | ||
| 195 | + Appearance stream (/N, /3): null | ||
| 196 | + Annotation: 18 0 R | ||
| 197 | + Field: 18 0 R | ||
| 198 | + Subtype: /Widget | ||
| 199 | + Rect: [151.3, 601.7, 163.6, 613.6] | ||
| 200 | + Appearance state: /Off | ||
| 201 | + Appearance stream (/N): 54 0 R | ||
| 202 | + Appearance stream (/N, /3): 52 0 R | ||
| 203 | + Annotation: 6 0 R | ||
| 204 | + Field: 6 0 R | ||
| 205 | + Subtype: /Widget | ||
| 206 | + Rect: [121.9, 559.1, 134.2, 571] | ||
| 207 | + Appearance state: /Off | ||
| 208 | + Appearance stream (/N): 19 0 R | ||
| 209 | + Appearance stream (/N, /3): null | ||
| 210 | + Annotation: 7 0 R | ||
| 211 | + Field: 7 0 R | ||
| 212 | + Subtype: /Widget | ||
| 213 | + Rect: [118.6, 527.7, 130.9, 539.6] | ||
| 214 | + Appearance state: /Yes | ||
| 215 | + Appearance stream (/N): 26 0 R | ||
| 216 | + Appearance stream (/N, /3): null | ||
| 217 | + Annotation: 8 0 R | ||
| 218 | + Field: 8 0 R | ||
| 219 | + Subtype: /Widget | ||
| 220 | + Rect: [118.6, 500.5, 130.9, 512.4] | ||
| 221 | + Appearance state: /Off | ||
| 222 | + Appearance stream (/N): 28 0 R | ||
| 223 | + Appearance stream (/N, /3): null | ||
| 224 | +Page: 40 0 R | ||
| 225 | +Page: 35 0 R | ||
| 226 | + Annotation: 32 0 R | ||
| 227 | + Field: 32 0 R | ||
| 228 | + Subtype: /Widget | ||
| 229 | + Rect: [118.6, 555.7, 130.9, 567.6] | ||
| 230 | + Appearance state: /Off | ||
| 231 | + Appearance stream (/N): 58 0 R | ||
| 232 | + Appearance stream (/N, /3): null | ||
| 233 | + Annotation: 33 0 R | ||
| 234 | + Field: 33 0 R | ||
| 235 | + Subtype: /Widget | ||
| 236 | + Rect: [119.3, 514.8, 131.6, 526.7] | ||
| 237 | + Appearance state: /2 | ||
| 238 | + Appearance stream (/N): 60 0 R | ||
| 239 | + Appearance stream (/N, /3): null | ||
| 240 | + Annotation: 34 0 R | ||
| 241 | + Field: 34 0 R | ||
| 242 | + Subtype: /Widget | ||
| 243 | + Rect: [121.3, 472.5, 133.6, 484.4] | ||
| 244 | + Appearance state: /Off | ||
| 245 | + Appearance stream (/N): 66 0 R | ||
| 246 | + Appearance stream (/N, /3): 64 0 R | ||
| 247 | + Annotation: 10 0 R | ||
| 248 | + Field: 10 0 R | ||
| 249 | + Subtype: /Widget | ||
| 250 | + Rect: [113.6, 378.5, 351.3, 396.3] | ||
| 251 | + Appearance stream (/N): 36 0 R | ||
| 252 | + Appearance stream (/N, /3): null | ||
| 253 | +test 43 done |
qpdf/qtest/qpdf/form-form-empty-from-odt.out
0 → 100644
| 1 | +iterating over form fields | ||
| 2 | +Field: 4 0 R | ||
| 3 | + Parent: none | ||
| 4 | + Fully qualified name: Text Box 1 | ||
| 5 | + Partial name: Text Box 1 | ||
| 6 | + Alternative name: Text Box 1 | ||
| 7 | + Mapping name: Text Box 1 | ||
| 8 | + Field type: /Tx | ||
| 9 | + Value: <feff> | ||
| 10 | + Value as string: | ||
| 11 | + Default value: <feff> | ||
| 12 | + Default value as string: | ||
| 13 | + Default appearance: 0.18039 0.20392 0.21176 rg /F2 12 Tf | ||
| 14 | + Quadding: 0 | ||
| 15 | + Annotation: 4 0 R | ||
| 16 | +Field: 6 0 R | ||
| 17 | + Parent: none | ||
| 18 | + Fully qualified name: Check Box 1 | ||
| 19 | + Partial name: Check Box 1 | ||
| 20 | + Alternative name: Check Box 1 | ||
| 21 | + Mapping name: Check Box 1 | ||
| 22 | + Field type: /Btn | ||
| 23 | + Value: /Off | ||
| 24 | + Value as string: | ||
| 25 | + Default value: /Off | ||
| 26 | + Default value as string: | ||
| 27 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 28 | + Quadding: 0 | ||
| 29 | + Annotation: 6 0 R | ||
| 30 | +Field: 7 0 R | ||
| 31 | + Parent: none | ||
| 32 | + Fully qualified name: Check Box 2 | ||
| 33 | + Partial name: Check Box 2 | ||
| 34 | + Alternative name: Check Box 2 | ||
| 35 | + Mapping name: Check Box 2 | ||
| 36 | + Field type: /Btn | ||
| 37 | + Value: /Yes | ||
| 38 | + Value as string: | ||
| 39 | + Default value: /Yes | ||
| 40 | + Default value as string: | ||
| 41 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 42 | + Quadding: 0 | ||
| 43 | + Annotation: 7 0 R | ||
| 44 | +Field: 8 0 R | ||
| 45 | + Parent: none | ||
| 46 | + Fully qualified name: Check Box 3 | ||
| 47 | + Partial name: Check Box 3 | ||
| 48 | + Alternative name: Check Box 3 | ||
| 49 | + Mapping name: Check Box 3 | ||
| 50 | + Field type: /Btn | ||
| 51 | + Value: /Off | ||
| 52 | + Value as string: | ||
| 53 | + Default value: /Off | ||
| 54 | + Default value as string: | ||
| 55 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 56 | + Quadding: 0 | ||
| 57 | + Annotation: 8 0 R | ||
| 58 | +Field: 10 0 R | ||
| 59 | + Parent: none | ||
| 60 | + Fully qualified name: Text Box 2 | ||
| 61 | + Partial name: Text Box 2 | ||
| 62 | + Alternative name: Text Box 2 | ||
| 63 | + Mapping name: Text Box 2 | ||
| 64 | + Field type: /Tx | ||
| 65 | + Value: <feff00730061006c00610064002003c002ac> | ||
| 66 | + Value as string: salad πʬ | ||
| 67 | + Default value: <feff00730061006c00610064002003c002ac> | ||
| 68 | + Default value as string: salad πʬ | ||
| 69 | + Default appearance: 0.18039 0.20392 0.21176 rg /F2 12 Tf | ||
| 70 | + Quadding: 0 | ||
| 71 | + Annotation: 10 0 R | ||
| 72 | +Field: 16 0 R | ||
| 73 | + Parent: 5 0 R | ||
| 74 | + Parent: none | ||
| 75 | + Fully qualified name: r1 | ||
| 76 | + Partial name: | ||
| 77 | + Alternative name: r1 | ||
| 78 | + Mapping name: r1 | ||
| 79 | + Field type: /Btn | ||
| 80 | + Value: /1 | ||
| 81 | + Value as string: | ||
| 82 | + Default value: /1 | ||
| 83 | + Default value as string: | ||
| 84 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 85 | + Quadding: 0 | ||
| 86 | + Annotation: 16 0 R | ||
| 87 | +Field: 17 0 R | ||
| 88 | + Parent: 5 0 R | ||
| 89 | + Parent: none | ||
| 90 | + Fully qualified name: r1 | ||
| 91 | + Partial name: | ||
| 92 | + Alternative name: r1 | ||
| 93 | + Mapping name: r1 | ||
| 94 | + Field type: /Btn | ||
| 95 | + Value: /1 | ||
| 96 | + Value as string: | ||
| 97 | + Default value: /1 | ||
| 98 | + Default value as string: | ||
| 99 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 100 | + Quadding: 0 | ||
| 101 | + Annotation: 17 0 R | ||
| 102 | +Field: 18 0 R | ||
| 103 | + Parent: 5 0 R | ||
| 104 | + Parent: none | ||
| 105 | + Fully qualified name: r1 | ||
| 106 | + Partial name: | ||
| 107 | + Alternative name: r1 | ||
| 108 | + Mapping name: r1 | ||
| 109 | + Field type: /Btn | ||
| 110 | + Value: /1 | ||
| 111 | + Value as string: | ||
| 112 | + Default value: /1 | ||
| 113 | + Default value as string: | ||
| 114 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 115 | + Quadding: 0 | ||
| 116 | + Annotation: 18 0 R | ||
| 117 | +Field: 32 0 R | ||
| 118 | + Parent: 9 0 R | ||
| 119 | + Parent: none | ||
| 120 | + Fully qualified name: r2 | ||
| 121 | + Partial name: | ||
| 122 | + Alternative name: r2 | ||
| 123 | + Mapping name: r2 | ||
| 124 | + Field type: /Btn | ||
| 125 | + Value: /2 | ||
| 126 | + Value as string: | ||
| 127 | + Default value: /2 | ||
| 128 | + Default value as string: | ||
| 129 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 130 | + Quadding: 0 | ||
| 131 | + Annotation: 32 0 R | ||
| 132 | +Field: 33 0 R | ||
| 133 | + Parent: 9 0 R | ||
| 134 | + Parent: none | ||
| 135 | + Fully qualified name: r2 | ||
| 136 | + Partial name: | ||
| 137 | + Alternative name: r2 | ||
| 138 | + Mapping name: r2 | ||
| 139 | + Field type: /Btn | ||
| 140 | + Value: /2 | ||
| 141 | + Value as string: | ||
| 142 | + Default value: /2 | ||
| 143 | + Default value as string: | ||
| 144 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 145 | + Quadding: 0 | ||
| 146 | + Annotation: 33 0 R | ||
| 147 | +Field: 34 0 R | ||
| 148 | + Parent: 9 0 R | ||
| 149 | + Parent: none | ||
| 150 | + Fully qualified name: r2 | ||
| 151 | + Partial name: | ||
| 152 | + Alternative name: r2 | ||
| 153 | + Mapping name: r2 | ||
| 154 | + Field type: /Btn | ||
| 155 | + Value: /2 | ||
| 156 | + Value as string: | ||
| 157 | + Default value: /2 | ||
| 158 | + Default value as string: | ||
| 159 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 160 | + Quadding: 0 | ||
| 161 | + Annotation: 34 0 R | ||
| 162 | +iterating over annotations per page | ||
| 163 | +Page: 11 0 R | ||
| 164 | + Annotation: 4 0 R | ||
| 165 | + Field: 4 0 R | ||
| 166 | + Subtype: /Widget | ||
| 167 | + Rect: [123.4, 692.1, 260.9, 706.7] | ||
| 168 | + Appearance stream (/N): 14 0 R | ||
| 169 | + Appearance stream (/N, /3): null | ||
| 170 | + Annotation: 16 0 R | ||
| 171 | + Field: 16 0 R | ||
| 172 | + Subtype: /Widget | ||
| 173 | + Rect: [149.3, 648.5, 161.6, 660.4] | ||
| 174 | + Appearance state: /1 | ||
| 175 | + Appearance stream (/N): 44 0 R | ||
| 176 | + Appearance stream (/N, /3): null | ||
| 177 | + Annotation: 17 0 R | ||
| 178 | + Field: 17 0 R | ||
| 179 | + Subtype: /Widget | ||
| 180 | + Rect: [152.7, 627.3, 165, 639.2] | ||
| 181 | + Appearance state: /Off | ||
| 182 | + Appearance stream (/N): 50 0 R | ||
| 183 | + Appearance stream (/N, /3): null | ||
| 184 | + Annotation: 18 0 R | ||
| 185 | + Field: 18 0 R | ||
| 186 | + Subtype: /Widget | ||
| 187 | + Rect: [151.3, 601.7, 163.6, 613.6] | ||
| 188 | + Appearance state: /Off | ||
| 189 | + Appearance stream (/N): 54 0 R | ||
| 190 | + Appearance stream (/N, /3): 52 0 R | ||
| 191 | + Annotation: 6 0 R | ||
| 192 | + Field: 6 0 R | ||
| 193 | + Subtype: /Widget | ||
| 194 | + Rect: [121.9, 559.1, 134.2, 571] | ||
| 195 | + Appearance state: /Off | ||
| 196 | + Appearance stream (/N): 19 0 R | ||
| 197 | + Appearance stream (/N, /3): null | ||
| 198 | + Annotation: 7 0 R | ||
| 199 | + Field: 7 0 R | ||
| 200 | + Subtype: /Widget | ||
| 201 | + Rect: [118.6, 527.7, 130.9, 539.6] | ||
| 202 | + Appearance state: /Yes | ||
| 203 | + Appearance stream (/N): 26 0 R | ||
| 204 | + Appearance stream (/N, /3): null | ||
| 205 | + Annotation: 8 0 R | ||
| 206 | + Field: 8 0 R | ||
| 207 | + Subtype: /Widget | ||
| 208 | + Rect: [118.6, 500.5, 130.9, 512.4] | ||
| 209 | + Appearance state: /Off | ||
| 210 | + Appearance stream (/N): 28 0 R | ||
| 211 | + Appearance stream (/N, /3): null | ||
| 212 | +Page: 40 0 R | ||
| 213 | +Page: 35 0 R | ||
| 214 | + Annotation: 32 0 R | ||
| 215 | + Field: 32 0 R | ||
| 216 | + Subtype: /Widget | ||
| 217 | + Rect: [118.6, 555.7, 130.9, 567.6] | ||
| 218 | + Appearance state: /Off | ||
| 219 | + Appearance stream (/N): 58 0 R | ||
| 220 | + Appearance stream (/N, /3): null | ||
| 221 | + Annotation: 33 0 R | ||
| 222 | + Field: 33 0 R | ||
| 223 | + Subtype: /Widget | ||
| 224 | + Rect: [119.3, 514.8, 131.6, 526.7] | ||
| 225 | + Appearance state: /2 | ||
| 226 | + Appearance stream (/N): 60 0 R | ||
| 227 | + Appearance stream (/N, /3): null | ||
| 228 | + Annotation: 34 0 R | ||
| 229 | + Field: 34 0 R | ||
| 230 | + Subtype: /Widget | ||
| 231 | + Rect: [121.3, 472.5, 133.6, 484.4] | ||
| 232 | + Appearance state: /Off | ||
| 233 | + Appearance stream (/N): 66 0 R | ||
| 234 | + Appearance stream (/N, /3): 64 0 R | ||
| 235 | + Annotation: 10 0 R | ||
| 236 | + Field: 10 0 R | ||
| 237 | + Subtype: /Widget | ||
| 238 | + Rect: [113.6, 378.5, 351.3, 396.3] | ||
| 239 | + Appearance stream (/N): 36 0 R | ||
| 240 | + Appearance stream (/N, /3): null | ||
| 241 | +test 43 done |
qpdf/qtest/qpdf/form-form-errors.out
0 → 100644
| 1 | +iterating over form fields | ||
| 2 | +WARNING: form-errors.pdf, object 4 0 at offset 625: loop detected while traversing /AcroForm | ||
| 3 | +WARNING: form-errors.pdf, object 5 0 at offset 993: encountered a direct object as a field or annotation while traversing /AcroForm; ignoring field or annotation | ||
| 4 | +WARNING: form-errors.pdf, object 15 0 at offset 3452: encountered a non-dictionary as a field or annotation while traversing /AcroForm; ignoring field or annotation | ||
| 5 | +WARNING: form-errors.pdf, object 16 0 at offset 3475: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 6 | +WARNING: form-errors.pdf, object 32 0 at offset 5974: this widget annotation is not reachable from /AcroForm in the document catalog | ||
| 7 | +Field: 4 0 R | ||
| 8 | + Parent: none | ||
| 9 | + Fully qualified name: Text Box 1 | ||
| 10 | + Partial name: Text Box 1 | ||
| 11 | + Alternative name: Text Box 1 | ||
| 12 | + Mapping name: Text Box 1 | ||
| 13 | + Field type: /Tx | ||
| 14 | + Value: <feff> | ||
| 15 | + Value as string: | ||
| 16 | + Default value: <feff> | ||
| 17 | + Default value as string: | ||
| 18 | + Default appearance: 0.18039 0.20392 0.21176 rg /F2 12 Tf | ||
| 19 | + Quadding: 0 | ||
| 20 | + Annotation: 4 0 R | ||
| 21 | +Field: 6 0 R | ||
| 22 | + Parent: none | ||
| 23 | + Fully qualified name: Check Box 1 | ||
| 24 | + Partial name: Check Box 1 | ||
| 25 | + Alternative name: Check Box 1 | ||
| 26 | + Mapping name: Check Box 1 | ||
| 27 | + Field type: /Btn | ||
| 28 | + Value: /Off | ||
| 29 | + Value as string: | ||
| 30 | + Default value: /Off | ||
| 31 | + Default value as string: | ||
| 32 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 33 | + Quadding: 0 | ||
| 34 | + Annotation: 6 0 R | ||
| 35 | +Field: 7 0 R | ||
| 36 | + Parent: none | ||
| 37 | + Fully qualified name: Check Box 2 | ||
| 38 | + Partial name: Check Box 2 | ||
| 39 | + Alternative name: Check Box 2 | ||
| 40 | + Mapping name: Check Box 2 | ||
| 41 | + Field type: /Btn | ||
| 42 | + Value: /Yes | ||
| 43 | + Value as string: | ||
| 44 | + Default value: /Yes | ||
| 45 | + Default value as string: | ||
| 46 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 47 | + Quadding: 0 | ||
| 48 | + Annotation: 7 0 R | ||
| 49 | +Field: 8 0 R | ||
| 50 | + Parent: none | ||
| 51 | + Fully qualified name: Check Box 3 | ||
| 52 | + Partial name: Check Box 3 | ||
| 53 | + Alternative name: Check Box 3 | ||
| 54 | + Mapping name: Check Box 3 | ||
| 55 | + Field type: /Btn | ||
| 56 | + Value: /Off | ||
| 57 | + Value as string: | ||
| 58 | + Default value: /Off | ||
| 59 | + Default value as string: | ||
| 60 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 61 | + Quadding: 0 | ||
| 62 | + Annotation: 8 0 R | ||
| 63 | +Field: 10 0 R | ||
| 64 | + Parent: none | ||
| 65 | + Fully qualified name: Text Box 2 | ||
| 66 | + Partial name: Text Box 2 | ||
| 67 | + Alternative name: Text Box 2 | ||
| 68 | + Mapping name: Text Box 2 | ||
| 69 | + Field type: /Tx | ||
| 70 | + Value: <feff00730061006c00610064002003c002ac> | ||
| 71 | + Value as string: salad πʬ | ||
| 72 | + Default value: <feff00730061006c00610064002003c002ac> | ||
| 73 | + Default value as string: salad πʬ | ||
| 74 | + Default appearance: 0.18039 0.20392 0.21176 rg /F2 12 Tf | ||
| 75 | + Quadding: 0 | ||
| 76 | + Annotation: 10 0 R | ||
| 77 | +Field: 16 0 R | ||
| 78 | + Parent: 5 0 R | ||
| 79 | + Parent: none | ||
| 80 | + Fully qualified name: r1 | ||
| 81 | + Partial name: | ||
| 82 | + Alternative name: r1 | ||
| 83 | + Mapping name: r1 | ||
| 84 | + Field type: /Btn | ||
| 85 | + Value: /1 | ||
| 86 | + Value as string: | ||
| 87 | + Default value: /1 | ||
| 88 | + Default value as string: | ||
| 89 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 90 | + Quadding: 0 | ||
| 91 | + Annotation: 16 0 R | ||
| 92 | +Field: 17 0 R | ||
| 93 | + Parent: 5 0 R | ||
| 94 | + Parent: none | ||
| 95 | + Fully qualified name: r1 | ||
| 96 | + Partial name: | ||
| 97 | + Alternative name: r1 | ||
| 98 | + Mapping name: r1 | ||
| 99 | + Field type: /Btn | ||
| 100 | + Value: /1 | ||
| 101 | + Value as string: | ||
| 102 | + Default value: /1 | ||
| 103 | + Default value as string: | ||
| 104 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 105 | + Quadding: 0 | ||
| 106 | + Annotation: 17 0 R | ||
| 107 | +Field: 18 0 R | ||
| 108 | + Parent: 5 0 R | ||
| 109 | + Parent: none | ||
| 110 | + Fully qualified name: r1 | ||
| 111 | + Partial name: | ||
| 112 | + Alternative name: r1 | ||
| 113 | + Mapping name: r1 | ||
| 114 | + Field type: /Btn | ||
| 115 | + Value: /1 | ||
| 116 | + Value as string: | ||
| 117 | + Default value: /1 | ||
| 118 | + Default value as string: | ||
| 119 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 120 | + Quadding: 0 | ||
| 121 | + Annotation: 18 0 R | ||
| 122 | +Field: 32 0 R | ||
| 123 | + Parent: 9 0 R | ||
| 124 | + Parent: none | ||
| 125 | + Fully qualified name: r2 | ||
| 126 | + Partial name: | ||
| 127 | + Alternative name: r2 | ||
| 128 | + Mapping name: r2 | ||
| 129 | + Field type: /Btn | ||
| 130 | + Value: /2 | ||
| 131 | + Value as string: | ||
| 132 | + Default value: /2 | ||
| 133 | + Default value as string: | ||
| 134 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 135 | + Quadding: 0 | ||
| 136 | + Annotation: 32 0 R | ||
| 137 | +Field: 33 0 R | ||
| 138 | + Parent: 9 0 R | ||
| 139 | + Parent: none | ||
| 140 | + Fully qualified name: r2 | ||
| 141 | + Partial name: | ||
| 142 | + Alternative name: r2 | ||
| 143 | + Mapping name: r2 | ||
| 144 | + Field type: /Btn | ||
| 145 | + Value: /2 | ||
| 146 | + Value as string: | ||
| 147 | + Default value: /2 | ||
| 148 | + Default value as string: | ||
| 149 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 150 | + Quadding: 0 | ||
| 151 | + Annotation: 33 0 R | ||
| 152 | +Field: 34 0 R | ||
| 153 | + Parent: 9 0 R | ||
| 154 | + Parent: none | ||
| 155 | + Fully qualified name: r2 | ||
| 156 | + Partial name: | ||
| 157 | + Alternative name: r2 | ||
| 158 | + Mapping name: r2 | ||
| 159 | + Field type: /Btn | ||
| 160 | + Value: /2 | ||
| 161 | + Value as string: | ||
| 162 | + Default value: /2 | ||
| 163 | + Default value as string: | ||
| 164 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 165 | + Quadding: 0 | ||
| 166 | + Annotation: 34 0 R | ||
| 167 | +iterating over annotations per page | ||
| 168 | +Page: 11 0 R | ||
| 169 | + Annotation: 4 0 R | ||
| 170 | + Field: 4 0 R | ||
| 171 | + Subtype: /Widget | ||
| 172 | + Rect: [123.4, 692.1, 260.9, 706.7] | ||
| 173 | + Appearance stream (/N): 14 0 R | ||
| 174 | + Appearance stream (/N, /3): null | ||
| 175 | + Annotation: 16 0 R | ||
| 176 | + Field: 16 0 R | ||
| 177 | + Subtype: /Widget | ||
| 178 | + Rect: [149.3, 648.5, 161.6, 660.4] | ||
| 179 | + Appearance state: /1 | ||
| 180 | + Appearance stream (/N): 44 0 R | ||
| 181 | + Appearance stream (/N, /3): null | ||
| 182 | + Annotation: 17 0 R | ||
| 183 | + Field: 17 0 R | ||
| 184 | + Subtype: /Widget | ||
| 185 | + Rect: [152.7, 627.3, 165, 639.2] | ||
| 186 | + Appearance state: /Off | ||
| 187 | + Appearance stream (/N): 50 0 R | ||
| 188 | + Appearance stream (/N, /3): null | ||
| 189 | + Annotation: 18 0 R | ||
| 190 | + Field: 18 0 R | ||
| 191 | + Subtype: /Widget | ||
| 192 | + Rect: [151.3, 601.7, 163.6, 613.6] | ||
| 193 | + Appearance state: /Off | ||
| 194 | + Appearance stream (/N): 54 0 R | ||
| 195 | + Appearance stream (/N, /3): 52 0 R | ||
| 196 | + Annotation: 6 0 R | ||
| 197 | + Field: 6 0 R | ||
| 198 | + Subtype: /Widget | ||
| 199 | + Rect: [121.9, 559.1, 134.2, 571] | ||
| 200 | + Appearance state: /Off | ||
| 201 | + Appearance stream (/N): 19 0 R | ||
| 202 | + Appearance stream (/N, /3): null | ||
| 203 | + Annotation: 7 0 R | ||
| 204 | + Field: 7 0 R | ||
| 205 | + Subtype: /Widget | ||
| 206 | + Rect: [118.6, 527.7, 130.9, 539.6] | ||
| 207 | + Appearance state: /Yes | ||
| 208 | + Appearance stream (/N): 26 0 R | ||
| 209 | + Appearance stream (/N, /3): null | ||
| 210 | + Annotation: 8 0 R | ||
| 211 | + Field: 8 0 R | ||
| 212 | + Subtype: /Widget | ||
| 213 | + Rect: [118.6, 500.5, 130.9, 512.4] | ||
| 214 | + Appearance state: /Off | ||
| 215 | + Appearance stream (/N): 28 0 R | ||
| 216 | + Appearance stream (/N, /3): null | ||
| 217 | +Page: 40 0 R | ||
| 218 | +Page: 35 0 R | ||
| 219 | + Annotation: 32 0 R | ||
| 220 | + Field: 32 0 R | ||
| 221 | + Subtype: /Widget | ||
| 222 | + Rect: [118.6, 555.7, 130.9, 567.6] | ||
| 223 | + Appearance state: /Off | ||
| 224 | + Appearance stream (/N): 58 0 R | ||
| 225 | + Appearance stream (/N, /3): null | ||
| 226 | + Annotation: 33 0 R | ||
| 227 | + Field: 33 0 R | ||
| 228 | + Subtype: /Widget | ||
| 229 | + Rect: [119.3, 514.8, 131.6, 526.7] | ||
| 230 | + Appearance state: /2 | ||
| 231 | + Appearance stream (/N): 60 0 R | ||
| 232 | + Appearance stream (/N, /3): null | ||
| 233 | + Annotation: 34 0 R | ||
| 234 | + Field: 34 0 R | ||
| 235 | + Subtype: /Widget | ||
| 236 | + Rect: [121.3, 472.5, 133.6, 484.4] | ||
| 237 | + Appearance state: /Off | ||
| 238 | + Appearance stream (/N): 66 0 R | ||
| 239 | + Appearance stream (/N, /3): 64 0 R | ||
| 240 | + Annotation: 10 0 R | ||
| 241 | + Field: 10 0 R | ||
| 242 | + Subtype: /Widget | ||
| 243 | + Rect: [113.6, 378.5, 351.3, 396.3] | ||
| 244 | + Appearance stream (/N): 36 0 R | ||
| 245 | + Appearance stream (/N, /3): null | ||
| 246 | +test 43 done |
qpdf/qtest/qpdf/form-form-filled-with-atril.out
0 → 100644
| 1 | +iterating over form fields | ||
| 2 | +Field: 4 0 R | ||
| 3 | + Parent: none | ||
| 4 | + Fully qualified name: Text Box 1 | ||
| 5 | + Partial name: Text Box 1 | ||
| 6 | + Alternative name: Text Box 1 | ||
| 7 | + Mapping name: Text Box 1 | ||
| 8 | + Field type: /Tx | ||
| 9 | + Value: <feff004800610067006f006f00670061006d00610067006f006f0067006c0065> | ||
| 10 | + Value as string: Hagoogamagoogle | ||
| 11 | + Default value: <feff> | ||
| 12 | + Default value as string: | ||
| 13 | + Default appearance: 0.18039 0.20392 0.21176 rg /F2 12 Tf | ||
| 14 | + Quadding: 0 | ||
| 15 | + Annotation: 4 0 R | ||
| 16 | +Field: 6 0 R | ||
| 17 | + Parent: none | ||
| 18 | + Fully qualified name: Check Box 1 | ||
| 19 | + Partial name: Check Box 1 | ||
| 20 | + Alternative name: Check Box 1 | ||
| 21 | + Mapping name: Check Box 1 | ||
| 22 | + Field type: /Btn | ||
| 23 | + Value: /Yes | ||
| 24 | + Value as string: | ||
| 25 | + Default value: /Off | ||
| 26 | + Default value as string: | ||
| 27 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 28 | + Quadding: 0 | ||
| 29 | + Annotation: 6 0 R | ||
| 30 | +Field: 7 0 R | ||
| 31 | + Parent: none | ||
| 32 | + Fully qualified name: Check Box 2 | ||
| 33 | + Partial name: Check Box 2 | ||
| 34 | + Alternative name: Check Box 2 | ||
| 35 | + Mapping name: Check Box 2 | ||
| 36 | + Field type: /Btn | ||
| 37 | + Value: /Yes | ||
| 38 | + Value as string: | ||
| 39 | + Default value: /Yes | ||
| 40 | + Default value as string: | ||
| 41 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 42 | + Quadding: 0 | ||
| 43 | + Annotation: 7 0 R | ||
| 44 | +Field: 8 0 R | ||
| 45 | + Parent: none | ||
| 46 | + Fully qualified name: Check Box 3 | ||
| 47 | + Partial name: Check Box 3 | ||
| 48 | + Alternative name: Check Box 3 | ||
| 49 | + Mapping name: Check Box 3 | ||
| 50 | + Field type: /Btn | ||
| 51 | + Value: /Off | ||
| 52 | + Value as string: | ||
| 53 | + Default value: /Off | ||
| 54 | + Default value as string: | ||
| 55 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 56 | + Quadding: 0 | ||
| 57 | + Annotation: 8 0 R | ||
| 58 | +Field: 10 0 R | ||
| 59 | + Parent: none | ||
| 60 | + Fully qualified name: Text Box 2 | ||
| 61 | + Partial name: Text Box 2 | ||
| 62 | + Alternative name: Text Box 2 | ||
| 63 | + Mapping name: Text Box 2 | ||
| 64 | + Field type: /Tx | ||
| 65 | + Value: <feff00730061006c00610064002003c002ac00200021> | ||
| 66 | + Value as string: salad πʬ ! | ||
| 67 | + Default value: <feff00730061006c00610064002003c002ac> | ||
| 68 | + Default value as string: salad πʬ | ||
| 69 | + Default appearance: 0.18039 0.20392 0.21176 rg /F2 12 Tf | ||
| 70 | + Quadding: 0 | ||
| 71 | + Annotation: 10 0 R | ||
| 72 | +Field: 16 0 R | ||
| 73 | + Parent: 5 0 R | ||
| 74 | + Parent: none | ||
| 75 | + Fully qualified name: r1 | ||
| 76 | + Partial name: | ||
| 77 | + Alternative name: r1 | ||
| 78 | + Mapping name: r1 | ||
| 79 | + Field type: /Btn | ||
| 80 | + Value: /3 | ||
| 81 | + Value as string: | ||
| 82 | + Default value: /1 | ||
| 83 | + Default value as string: | ||
| 84 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 85 | + Quadding: 0 | ||
| 86 | + Annotation: 16 0 R | ||
| 87 | +Field: 17 0 R | ||
| 88 | + Parent: 5 0 R | ||
| 89 | + Parent: none | ||
| 90 | + Fully qualified name: r1 | ||
| 91 | + Partial name: | ||
| 92 | + Alternative name: r1 | ||
| 93 | + Mapping name: r1 | ||
| 94 | + Field type: /Btn | ||
| 95 | + Value: /3 | ||
| 96 | + Value as string: | ||
| 97 | + Default value: /1 | ||
| 98 | + Default value as string: | ||
| 99 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 100 | + Quadding: 0 | ||
| 101 | + Annotation: 17 0 R | ||
| 102 | +Field: 18 0 R | ||
| 103 | + Parent: 5 0 R | ||
| 104 | + Parent: none | ||
| 105 | + Fully qualified name: r1 | ||
| 106 | + Partial name: | ||
| 107 | + Alternative name: r1 | ||
| 108 | + Mapping name: r1 | ||
| 109 | + Field type: /Btn | ||
| 110 | + Value: /3 | ||
| 111 | + Value as string: | ||
| 112 | + Default value: /1 | ||
| 113 | + Default value as string: | ||
| 114 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 115 | + Quadding: 0 | ||
| 116 | + Annotation: 18 0 R | ||
| 117 | +Field: 32 0 R | ||
| 118 | + Parent: 9 0 R | ||
| 119 | + Parent: none | ||
| 120 | + Fully qualified name: r2 | ||
| 121 | + Partial name: | ||
| 122 | + Alternative name: r2 | ||
| 123 | + Mapping name: r2 | ||
| 124 | + Field type: /Btn | ||
| 125 | + Value: /2 | ||
| 126 | + Value as string: | ||
| 127 | + Default value: /2 | ||
| 128 | + Default value as string: | ||
| 129 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 130 | + Quadding: 0 | ||
| 131 | + Annotation: 32 0 R | ||
| 132 | +Field: 33 0 R | ||
| 133 | + Parent: 9 0 R | ||
| 134 | + Parent: none | ||
| 135 | + Fully qualified name: r2 | ||
| 136 | + Partial name: | ||
| 137 | + Alternative name: r2 | ||
| 138 | + Mapping name: r2 | ||
| 139 | + Field type: /Btn | ||
| 140 | + Value: /2 | ||
| 141 | + Value as string: | ||
| 142 | + Default value: /2 | ||
| 143 | + Default value as string: | ||
| 144 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 145 | + Quadding: 0 | ||
| 146 | + Annotation: 33 0 R | ||
| 147 | +Field: 34 0 R | ||
| 148 | + Parent: 9 0 R | ||
| 149 | + Parent: none | ||
| 150 | + Fully qualified name: r2 | ||
| 151 | + Partial name: | ||
| 152 | + Alternative name: r2 | ||
| 153 | + Mapping name: r2 | ||
| 154 | + Field type: /Btn | ||
| 155 | + Value: /2 | ||
| 156 | + Value as string: | ||
| 157 | + Default value: /2 | ||
| 158 | + Default value as string: | ||
| 159 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 160 | + Quadding: 0 | ||
| 161 | + Annotation: 34 0 R | ||
| 162 | +iterating over annotations per page | ||
| 163 | +Page: 11 0 R | ||
| 164 | + Annotation: 4 0 R | ||
| 165 | + Field: 4 0 R | ||
| 166 | + Subtype: /Widget | ||
| 167 | + Rect: [123.4, 692.1, 260.9, 706.7] | ||
| 168 | + Appearance stream (/N): null | ||
| 169 | + Appearance stream (/N, /3): null | ||
| 170 | + Annotation: 16 0 R | ||
| 171 | + Field: 16 0 R | ||
| 172 | + Subtype: /Widget | ||
| 173 | + Rect: [149.3, 648.5, 161.6, 660.4] | ||
| 174 | + Appearance state: /Off | ||
| 175 | + Appearance stream (/N): 46 0 R | ||
| 176 | + Appearance stream (/N, /3): null | ||
| 177 | + Annotation: 17 0 R | ||
| 178 | + Field: 17 0 R | ||
| 179 | + Subtype: /Widget | ||
| 180 | + Rect: [152.7, 627.3, 165, 639.2] | ||
| 181 | + Appearance state: /Off | ||
| 182 | + Appearance stream (/N): 50 0 R | ||
| 183 | + Appearance stream (/N, /3): null | ||
| 184 | + Annotation: 18 0 R | ||
| 185 | + Field: 18 0 R | ||
| 186 | + Subtype: /Widget | ||
| 187 | + Rect: [151.3, 601.7, 163.6, 613.6] | ||
| 188 | + Appearance state: /3 | ||
| 189 | + Appearance stream (/N): 52 0 R | ||
| 190 | + Appearance stream (/N, /3): 52 0 R | ||
| 191 | + Annotation: 6 0 R | ||
| 192 | + Field: 6 0 R | ||
| 193 | + Subtype: /Widget | ||
| 194 | + Rect: [121.9, 559.1, 134.2, 571] | ||
| 195 | + Appearance state: /Yes | ||
| 196 | + Appearance stream (/N): 21 0 R | ||
| 197 | + Appearance stream (/N, /3): null | ||
| 198 | + Annotation: 7 0 R | ||
| 199 | + Field: 7 0 R | ||
| 200 | + Subtype: /Widget | ||
| 201 | + Rect: [118.6, 527.7, 130.9, 539.6] | ||
| 202 | + Appearance state: /Yes | ||
| 203 | + Appearance stream (/N): 26 0 R | ||
| 204 | + Appearance stream (/N, /3): null | ||
| 205 | + Annotation: 8 0 R | ||
| 206 | + Field: 8 0 R | ||
| 207 | + Subtype: /Widget | ||
| 208 | + Rect: [118.6, 500.5, 130.9, 512.4] | ||
| 209 | + Appearance state: /Off | ||
| 210 | + Appearance stream (/N): 28 0 R | ||
| 211 | + Appearance stream (/N, /3): null | ||
| 212 | +Page: 40 0 R | ||
| 213 | +Page: 35 0 R | ||
| 214 | + Annotation: 32 0 R | ||
| 215 | + Field: 32 0 R | ||
| 216 | + Subtype: /Widget | ||
| 217 | + Rect: [118.6, 555.7, 130.9, 567.6] | ||
| 218 | + Appearance state: /Off | ||
| 219 | + Appearance stream (/N): 58 0 R | ||
| 220 | + Appearance stream (/N, /3): null | ||
| 221 | + Annotation: 33 0 R | ||
| 222 | + Field: 33 0 R | ||
| 223 | + Subtype: /Widget | ||
| 224 | + Rect: [119.3, 514.8, 131.6, 526.7] | ||
| 225 | + Appearance state: /2 | ||
| 226 | + Appearance stream (/N): 60 0 R | ||
| 227 | + Appearance stream (/N, /3): null | ||
| 228 | + Annotation: 34 0 R | ||
| 229 | + Field: 34 0 R | ||
| 230 | + Subtype: /Widget | ||
| 231 | + Rect: [121.3, 472.5, 133.6, 484.4] | ||
| 232 | + Appearance state: /Off | ||
| 233 | + Appearance stream (/N): 66 0 R | ||
| 234 | + Appearance stream (/N, /3): 64 0 R | ||
| 235 | + Annotation: 10 0 R | ||
| 236 | + Field: 10 0 R | ||
| 237 | + Subtype: /Widget | ||
| 238 | + Rect: [113.6, 378.5, 351.3, 396.3] | ||
| 239 | + Appearance stream (/N): null | ||
| 240 | + Appearance stream (/N, /3): null | ||
| 241 | +test 43 done |
qpdf/qtest/qpdf/form-form-mod1.out
0 → 100644
| 1 | +iterating over form fields | ||
| 2 | +Field: 4 0 R | ||
| 3 | + Parent: none | ||
| 4 | + Fully qualified name: Text Box 1 | ||
| 5 | + Partial name: Text Box 1 | ||
| 6 | + Alternative name: Text Box 1 | ||
| 7 | + Mapping name: Text Box 1 | ||
| 8 | + Field type: /Tx | ||
| 9 | + Value: <feff> | ||
| 10 | + Value as string: | ||
| 11 | + Default value: <feff> | ||
| 12 | + Default value as string: | ||
| 13 | + Default appearance: 0.18039 0.20392 0.21176 rg /F2 12 Tf | ||
| 14 | + Quadding: 0 | ||
| 15 | + Annotation: 83 0 R | ||
| 16 | +Field: 6 0 R | ||
| 17 | + Parent: none | ||
| 18 | + Fully qualified name: Check Box 1 | ||
| 19 | + Partial name: Check Box 1 | ||
| 20 | + Alternative name: Check Box 1 | ||
| 21 | + Mapping name: Check Box 1 | ||
| 22 | + Field type: /Btn | ||
| 23 | + Value: /Off | ||
| 24 | + Value as string: | ||
| 25 | + Default value: /Off | ||
| 26 | + Default value as string: | ||
| 27 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 28 | + Quadding: 0 | ||
| 29 | + Annotation: 6 0 R | ||
| 30 | +Field: 7 0 R | ||
| 31 | + Parent: none | ||
| 32 | + Fully qualified name: Check Box 2 | ||
| 33 | + Partial name: Check Box 2 | ||
| 34 | + Alternative name: Check Box 2 | ||
| 35 | + Mapping name: Check Box 2 | ||
| 36 | + Field type: /Btn | ||
| 37 | + Value: /Yes | ||
| 38 | + Value as string: | ||
| 39 | + Default value: /Yes | ||
| 40 | + Default value as string: | ||
| 41 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 42 | + Quadding: 0 | ||
| 43 | + Annotation: 7 0 R | ||
| 44 | +Field: 8 0 R | ||
| 45 | + Parent: none | ||
| 46 | + Fully qualified name: Check Box 3 | ||
| 47 | + Partial name: Check Box 3 | ||
| 48 | + Alternative name: Check Box 3 | ||
| 49 | + Mapping name: Check Box 3 | ||
| 50 | + Field type: /Btn | ||
| 51 | + Value: /Off | ||
| 52 | + Value as string: | ||
| 53 | + Default value: /Off | ||
| 54 | + Default value as string: | ||
| 55 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 56 | + Quadding: 0 | ||
| 57 | + Annotation: 8 0 R | ||
| 58 | +Field: 10 0 R | ||
| 59 | + Parent: none | ||
| 60 | + Fully qualified name: Text Box 2 | ||
| 61 | + Partial name: Text Box 2 | ||
| 62 | + Alternative name: Text Box 2 | ||
| 63 | + Mapping name: Text Box 2 | ||
| 64 | + Field type: /Tx | ||
| 65 | + Value: <feff00730061006c00610064002003c002ac> | ||
| 66 | + Value as string: salad πʬ | ||
| 67 | + Default value: <feff00730061006c00610064002003c002ac> | ||
| 68 | + Default value as string: salad πʬ | ||
| 69 | + Default appearance: 0.18039 0.20392 0.21176 rg /F2 12 Tf | ||
| 70 | + Quadding: 1 | ||
| 71 | + Annotation: 10 0 R | ||
| 72 | +Field: 16 0 R | ||
| 73 | + Parent: 5 0 R | ||
| 74 | + Parent: none | ||
| 75 | + Fully qualified name: r1.choice1 | ||
| 76 | + Partial name: choice1 | ||
| 77 | + Alternative name: chice 1 | ||
| 78 | + Mapping name: choice 1 TM | ||
| 79 | + Field type: /Btn | ||
| 80 | + Value: /1 | ||
| 81 | + Value as string: | ||
| 82 | + Default value: /1 | ||
| 83 | + Default value as string: | ||
| 84 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 85 | + Quadding: 0 | ||
| 86 | + Annotation: 16 0 R | ||
| 87 | +Field: 17 0 R | ||
| 88 | + Parent: 5 0 R | ||
| 89 | + Parent: none | ||
| 90 | + Fully qualified name: r1 | ||
| 91 | + Partial name: | ||
| 92 | + Alternative name: r1 | ||
| 93 | + Mapping name: r1 | ||
| 94 | + Field type: /Btn | ||
| 95 | + Value: /1 | ||
| 96 | + Value as string: | ||
| 97 | + Default value: /1 | ||
| 98 | + Default value as string: | ||
| 99 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 100 | + Quadding: 0 | ||
| 101 | + Annotation: 17 0 R | ||
| 102 | +Field: 18 0 R | ||
| 103 | + Parent: 5 0 R | ||
| 104 | + Parent: none | ||
| 105 | + Fully qualified name: r1 | ||
| 106 | + Partial name: | ||
| 107 | + Alternative name: r1 | ||
| 108 | + Mapping name: r1 | ||
| 109 | + Field type: /Btn | ||
| 110 | + Value: /1 | ||
| 111 | + Value as string: | ||
| 112 | + Default value: /1 | ||
| 113 | + Default value as string: | ||
| 114 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 115 | + Quadding: 0 | ||
| 116 | + Annotation: 18 0 R | ||
| 117 | +Field: 32 0 R | ||
| 118 | + Parent: 9 0 R | ||
| 119 | + Parent: none | ||
| 120 | + Fully qualified name: r2 | ||
| 121 | + Partial name: | ||
| 122 | + Alternative name: r2 | ||
| 123 | + Mapping name: r2 | ||
| 124 | + Field type: /Btn | ||
| 125 | + Value: /2 | ||
| 126 | + Value as string: | ||
| 127 | + Default value: /2 | ||
| 128 | + Default value as string: | ||
| 129 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 130 | + Quadding: 0 | ||
| 131 | + Annotation: 32 0 R | ||
| 132 | +Field: 33 0 R | ||
| 133 | + Parent: 9 0 R | ||
| 134 | + Parent: none | ||
| 135 | + Fully qualified name: r2 | ||
| 136 | + Partial name: | ||
| 137 | + Alternative name: r2 | ||
| 138 | + Mapping name: r2 | ||
| 139 | + Field type: /Btn | ||
| 140 | + Value: /2 | ||
| 141 | + Value as string: | ||
| 142 | + Default value: /2 | ||
| 143 | + Default value as string: | ||
| 144 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 145 | + Quadding: 0 | ||
| 146 | + Annotation: 33 0 R | ||
| 147 | +Field: 34 0 R | ||
| 148 | + Parent: 9 0 R | ||
| 149 | + Parent: none | ||
| 150 | + Fully qualified name: r2 | ||
| 151 | + Partial name: | ||
| 152 | + Alternative name: r2 | ||
| 153 | + Mapping name: r2 | ||
| 154 | + Field type: /Btn | ||
| 155 | + Value: /2 | ||
| 156 | + Value as string: | ||
| 157 | + Default value: /2 | ||
| 158 | + Default value as string: | ||
| 159 | + Default appearance: 0.18039 0.20392 0.21176 rg /ZaDi 0 Tf | ||
| 160 | + Quadding: 0 | ||
| 161 | + Annotation: 34 0 R | ||
| 162 | +iterating over annotations per page | ||
| 163 | +Page: 11 0 R | ||
| 164 | + Annotation: 83 0 R | ||
| 165 | + Field: 4 0 R | ||
| 166 | + Subtype: /Widget | ||
| 167 | + Rect: [123.4, 692.1, 260.9, 706.7] | ||
| 168 | + Appearance stream (/N): 14 0 R | ||
| 169 | + Appearance stream (/N, /3): null | ||
| 170 | + Annotation: 16 0 R | ||
| 171 | + Field: 16 0 R | ||
| 172 | + Subtype: /Widget | ||
| 173 | + Rect: [149.3, 648.5, 161.6, 660.4] | ||
| 174 | + Appearance state: /1 | ||
| 175 | + Appearance stream (/N): 44 0 R | ||
| 176 | + Appearance stream (/N, /3): null | ||
| 177 | + Annotation: 17 0 R | ||
| 178 | + Field: 17 0 R | ||
| 179 | + Subtype: /Widget | ||
| 180 | + Rect: [152.7, 627.3, 165, 639.2] | ||
| 181 | + Appearance state: /Off | ||
| 182 | + Appearance stream (/N): 50 0 R | ||
| 183 | + Appearance stream (/N, /3): null | ||
| 184 | + Annotation: 18 0 R | ||
| 185 | + Field: 18 0 R | ||
| 186 | + Subtype: /Widget | ||
| 187 | + Rect: [151.3, 601.7, 163.6, 613.6] | ||
| 188 | + Appearance state: /Off | ||
| 189 | + Appearance stream (/N): 54 0 R | ||
| 190 | + Appearance stream (/N, /3): 52 0 R | ||
| 191 | + Annotation: 6 0 R | ||
| 192 | + Field: 6 0 R | ||
| 193 | + Subtype: /Widget | ||
| 194 | + Rect: [121.9, 559.1, 134.2, 571] | ||
| 195 | + Appearance state: /Off | ||
| 196 | + Appearance stream (/N): 19 0 R | ||
| 197 | + Appearance stream (/N, /3): null | ||
| 198 | + Annotation: 7 0 R | ||
| 199 | + Field: 7 0 R | ||
| 200 | + Subtype: /Widget | ||
| 201 | + Rect: [118.6, 527.7, 130.9, 539.6] | ||
| 202 | + Appearance state: /Yes | ||
| 203 | + Appearance stream (/N): 26 0 R | ||
| 204 | + Appearance stream (/N, /3): null | ||
| 205 | + Annotation: 8 0 R | ||
| 206 | + Field: 8 0 R | ||
| 207 | + Subtype: /Widget | ||
| 208 | + Rect: [118.6, 500.5, 130.9, 512.4] | ||
| 209 | + Appearance state: /Off | ||
| 210 | + Appearance stream (/N): 28 0 R | ||
| 211 | + Appearance stream (/N, /3): null | ||
| 212 | +Page: 40 0 R | ||
| 213 | +Page: 35 0 R | ||
| 214 | + Annotation: 32 0 R | ||
| 215 | + Field: 32 0 R | ||
| 216 | + Subtype: /Widget | ||
| 217 | + Rect: [118.6, 555.7, 130.9, 567.6] | ||
| 218 | + Appearance state: /Off | ||
| 219 | + Appearance stream (/N): 58 0 R | ||
| 220 | + Appearance stream (/N, /3): null | ||
| 221 | + Annotation: 33 0 R | ||
| 222 | + Field: 33 0 R | ||
| 223 | + Subtype: /Widget | ||
| 224 | + Rect: [119.3, 514.8, 131.6, 526.7] | ||
| 225 | + Appearance state: /2 | ||
| 226 | + Appearance stream (/N): 60 0 R | ||
| 227 | + Appearance stream (/N, /3): null | ||
| 228 | + Annotation: 34 0 R | ||
| 229 | + Field: 34 0 R | ||
| 230 | + Subtype: /Widget | ||
| 231 | + Rect: [121.3, 472.5, 133.6, 484.4] | ||
| 232 | + Appearance state: /Off | ||
| 233 | + Appearance stream (/N): 66 0 R | ||
| 234 | + Appearance stream (/N, /3): 64 0 R | ||
| 235 | + Annotation: 10 0 R | ||
| 236 | + Field: 10 0 R | ||
| 237 | + Subtype: /Widget | ||
| 238 | + Rect: [113.6, 378.5, 351.3, 396.3] | ||
| 239 | + Appearance stream (/N): 36 0 R | ||
| 240 | + Appearance stream (/N, /3): null | ||
| 241 | +test 43 done |
qpdf/qtest/qpdf/form-minimal.out
0 → 100644
| 1 | +no forms |
qpdf/qtest/qpdf/form-mod1.pdf
0 → 100644
No preview for this file type
qpdf/qtest/storage/README
0 → 100644
qpdf/qtest/storage/form.odt
0 → 100644
No preview for this file type
qpdf/qtest/storage/form.pdf
0 → 100644
No preview for this file type
qpdf/test_driver.cc
| @@ -5,6 +5,7 @@ | @@ -5,6 +5,7 @@ | ||
| 5 | 5 | ||
| 6 | #include <qpdf/QPDFPageDocumentHelper.hh> | 6 | #include <qpdf/QPDFPageDocumentHelper.hh> |
| 7 | #include <qpdf/QPDFPageObjectHelper.hh> | 7 | #include <qpdf/QPDFPageObjectHelper.hh> |
| 8 | +#include <qpdf/QPDFAcroFormDocumentHelper.hh> | ||
| 8 | #include <qpdf/QUtil.hh> | 9 | #include <qpdf/QUtil.hh> |
| 9 | #include <qpdf/QTC.hh> | 10 | #include <qpdf/QTC.hh> |
| 10 | #include <qpdf/Pl_StdioFile.hh> | 11 | #include <qpdf/Pl_StdioFile.hh> |
| @@ -153,6 +154,13 @@ static QPDFObjectHandle createPageContents(QPDF& pdf, std::string const& text) | @@ -153,6 +154,13 @@ static QPDFObjectHandle createPageContents(QPDF& pdf, std::string const& text) | ||
| 153 | return QPDFObjectHandle::newStream(&pdf, contents); | 154 | return QPDFObjectHandle::newStream(&pdf, contents); |
| 154 | } | 155 | } |
| 155 | 156 | ||
| 157 | +static void print_rect(std::ostream& out, | ||
| 158 | + QPDFObjectHandle::Rectangle const& r) | ||
| 159 | +{ | ||
| 160 | + out << "[" << r.llx << ", " << r.lly << ", " | ||
| 161 | + << r.urx << ", " << r.ury << "]"; | ||
| 162 | +} | ||
| 163 | + | ||
| 156 | void runtest(int n, char const* filename1, char const* arg2) | 164 | void runtest(int n, char const* filename1, char const* arg2) |
| 157 | { | 165 | { |
| 158 | // Most tests here are crafted to work on specific files. Look at | 166 | // Most tests here are crafted to work on specific files. Look at |
| @@ -1474,6 +1482,108 @@ void runtest(int n, char const* filename1, char const* arg2) | @@ -1474,6 +1482,108 @@ void runtest(int n, char const* filename1, char const* arg2) | ||
| 1474 | (r1.urx > 5.59) && (r1.urx < 5.61) && | 1482 | (r1.urx > 5.59) && (r1.urx < 5.61) && |
| 1475 | (r1.ury > 7.79) && (r1.ury < 7.81)); | 1483 | (r1.ury > 7.79) && (r1.ury < 7.81)); |
| 1476 | } | 1484 | } |
| 1485 | + else if (n == 43) | ||
| 1486 | + { | ||
| 1487 | + // Forms | ||
| 1488 | + QPDFAcroFormDocumentHelper afdh(pdf); | ||
| 1489 | + if (! afdh.hasAcroForm()) | ||
| 1490 | + { | ||
| 1491 | + std::cout << "no forms\n"; | ||
| 1492 | + return; | ||
| 1493 | + } | ||
| 1494 | + std::cout << "iterating over form fields\n"; | ||
| 1495 | + std::vector<QPDFFormFieldObjectHelper> form_fields = | ||
| 1496 | + afdh.getFormFields(); | ||
| 1497 | + for (std::vector<QPDFFormFieldObjectHelper>::iterator iter = | ||
| 1498 | + form_fields.begin(); | ||
| 1499 | + iter != form_fields.end(); ++iter) | ||
| 1500 | + { | ||
| 1501 | + QPDFFormFieldObjectHelper ffh(*iter); | ||
| 1502 | + std::cout << "Field: " << ffh.getObjectHandle().unparse() | ||
| 1503 | + << std::endl; | ||
| 1504 | + QPDFFormFieldObjectHelper node = ffh; | ||
| 1505 | + while (! node.isNull()) | ||
| 1506 | + { | ||
| 1507 | + QPDFFormFieldObjectHelper parent(node.getParent()); | ||
| 1508 | + std::cout << " Parent: " | ||
| 1509 | + << (parent.isNull() | ||
| 1510 | + ? "none" | ||
| 1511 | + : parent.getObjectHandle().unparse()) | ||
| 1512 | + << std::endl; | ||
| 1513 | + node = parent; | ||
| 1514 | + } | ||
| 1515 | + std::cout << " Fully qualified name: " | ||
| 1516 | + << ffh.getFullyQualifiedName() << std::endl; | ||
| 1517 | + std::cout << " Partial name: " | ||
| 1518 | + << ffh.getPartialName() << std::endl; | ||
| 1519 | + std::cout << " Alternative name: " | ||
| 1520 | + << ffh.getAlternativeName() << std::endl; | ||
| 1521 | + std::cout << " Mapping name: " | ||
| 1522 | + << ffh.getMappingName() << std::endl; | ||
| 1523 | + std::cout << " Field type: " | ||
| 1524 | + << ffh.getFieldType() << std::endl; | ||
| 1525 | + std::cout << " Value: " | ||
| 1526 | + << ffh.getValue().unparse() << std::endl; | ||
| 1527 | + std::cout << " Value as string: " | ||
| 1528 | + << ffh.getValueAsString() << std::endl; | ||
| 1529 | + std::cout << " Default value: " | ||
| 1530 | + << ffh.getDefaultValue().unparse() << std::endl; | ||
| 1531 | + std::cout << " Default value as string: " | ||
| 1532 | + << ffh.getDefaultValueAsString() << std::endl; | ||
| 1533 | + std::cout << " Default appearance: " | ||
| 1534 | + << ffh.getDefaultAppearance() << std::endl; | ||
| 1535 | + std::cout << " Quadding: " | ||
| 1536 | + << ffh.getQuadding() << std::endl; | ||
| 1537 | + std::vector<QPDFAnnotationObjectHelper> annotations = | ||
| 1538 | + afdh.getAnnotationsForField(ffh); | ||
| 1539 | + for (std::vector<QPDFAnnotationObjectHelper>::iterator i2 = | ||
| 1540 | + annotations.begin(); | ||
| 1541 | + i2 != annotations.end(); ++i2) | ||
| 1542 | + { | ||
| 1543 | + std::cout << " Annotation: " | ||
| 1544 | + << (*i2).getObjectHandle().unparse() << std::endl; | ||
| 1545 | + } | ||
| 1546 | + } | ||
| 1547 | + std::cout << "iterating over annotations per page\n"; | ||
| 1548 | + std::vector<QPDFPageObjectHelper> pages = | ||
| 1549 | + QPDFPageDocumentHelper(pdf).getAllPages(); | ||
| 1550 | + for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin(); | ||
| 1551 | + iter != pages.end(); ++iter) | ||
| 1552 | + { | ||
| 1553 | + std::cout << "Page: " << (*iter).getObjectHandle().unparse() | ||
| 1554 | + << std::endl; | ||
| 1555 | + std::vector<QPDFAnnotationObjectHelper> annotations = | ||
| 1556 | + afdh.getWidgetAnnotationsForPage(*iter); | ||
| 1557 | + for (std::vector<QPDFAnnotationObjectHelper>::iterator i2 = | ||
| 1558 | + annotations.begin(); | ||
| 1559 | + i2 != annotations.end(); ++i2) | ||
| 1560 | + { | ||
| 1561 | + QPDFAnnotationObjectHelper ah(*i2); | ||
| 1562 | + std::cout << " Annotation: " << ah.getObjectHandle().unparse() | ||
| 1563 | + << std::endl; | ||
| 1564 | + std::cout << " Field: " | ||
| 1565 | + << (afdh.getFieldForAnnotation(ah). | ||
| 1566 | + getObjectHandle().unparse()) | ||
| 1567 | + << std::endl; | ||
| 1568 | + std::cout << " Subtype: " << ah.getSubtype() << std::endl; | ||
| 1569 | + std::cout << " Rect: "; | ||
| 1570 | + print_rect(std::cout, ah.getRect()); | ||
| 1571 | + std::cout << std::endl; | ||
| 1572 | + std::string state = ah.getAppearanceState(); | ||
| 1573 | + if (! state.empty()) | ||
| 1574 | + { | ||
| 1575 | + std::cout << " Appearance state: " << state | ||
| 1576 | + << std::endl; | ||
| 1577 | + } | ||
| 1578 | + std::cout << " Appearance stream (/N): " | ||
| 1579 | + << ah.getAppearanceStream("/N").unparse() | ||
| 1580 | + << std::endl; | ||
| 1581 | + std::cout << " Appearance stream (/N, /3): " | ||
| 1582 | + << ah.getAppearanceStream("/N", "/3").unparse() | ||
| 1583 | + << std::endl; | ||
| 1584 | + } | ||
| 1585 | + } | ||
| 1586 | + } | ||
| 1477 | else | 1587 | else |
| 1478 | { | 1588 | { |
| 1479 | throw std::runtime_error(std::string("invalid test ") + | 1589 | throw std::runtime_error(std::string("invalid test ") + |