hexapdf 0.47.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +65 -16
- data/lib/hexapdf/cli.rb +14 -1
- data/lib/hexapdf/composer.rb +7 -0
- data/lib/hexapdf/configuration.rb +2 -0
- data/lib/hexapdf/content/parser.rb +3 -1
- data/lib/hexapdf/digital_signature/cms_handler.rb +13 -0
- data/lib/hexapdf/digital_signature/signature.rb +1 -1
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +1 -0
- data/lib/hexapdf/document.rb +14 -3
- data/lib/hexapdf/font/cmap/writer.rb +58 -4
- data/lib/hexapdf/font/cmap.rb +7 -0
- data/lib/hexapdf/font/true_type_wrapper.rb +41 -16
- data/lib/hexapdf/layout/text_fragment.rb +2 -1
- data/lib/hexapdf/object.rb +1 -1
- data/lib/hexapdf/parser.rb +6 -2
- data/lib/hexapdf/reference.rb +1 -1
- data/lib/hexapdf/task/merge_acro_form.rb +164 -0
- data/lib/hexapdf/task.rb +1 -0
- data/lib/hexapdf/tokenizer.rb +2 -0
- data/lib/hexapdf/type/acro_form/form.rb +14 -27
- data/lib/hexapdf/type/acro_form/signature_field.rb +16 -6
- data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
- data/lib/hexapdf/type/actions/go_to.rb +1 -0
- data/lib/hexapdf/type/actions/go_to_r.rb +1 -0
- data/lib/hexapdf/type/actions/launch.rb +5 -1
- data/lib/hexapdf/type/annotation.rb +6 -1
- data/lib/hexapdf/type/annotations/markup_annotation.rb +14 -1
- data/lib/hexapdf/type/catalog.rb +3 -0
- data/lib/hexapdf/type/cid_font.rb +4 -1
- data/lib/hexapdf/type/file_specification.rb +17 -14
- data/lib/hexapdf/type/font_descriptor.rb +4 -3
- data/lib/hexapdf/type/font_simple.rb +3 -1
- data/lib/hexapdf/type/font_true_type.rb +2 -0
- data/lib/hexapdf/type/font_type0.rb +1 -1
- data/lib/hexapdf/type/font_type1.rb +7 -0
- data/lib/hexapdf/type/font_type3.rb +0 -1
- data/lib/hexapdf/type/form.rb +5 -2
- data/lib/hexapdf/type/graphics_state_parameter.rb +7 -4
- data/lib/hexapdf/type/image.rb +8 -4
- data/lib/hexapdf/type/info.rb +2 -2
- data/lib/hexapdf/type/mark_information.rb +2 -2
- data/lib/hexapdf/type/optional_content_configuration.rb +1 -1
- data/lib/hexapdf/type/optional_content_membership.rb +1 -1
- data/lib/hexapdf/type/page.rb +5 -3
- data/lib/hexapdf/type/resources.rb +6 -6
- data/lib/hexapdf/type/viewer_preferences.rb +4 -3
- data/lib/hexapdf/utils/sorted_tree_node.rb +12 -2
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/writer.rb +1 -0
- data/lib/hexapdf/xref_section.rb +20 -4
- data/test/hexapdf/common_tokenizer_tests.rb +5 -0
- data/test/hexapdf/digital_signature/signing/test_default_handler.rb +6 -0
- data/test/hexapdf/digital_signature/test_cms_handler.rb +12 -7
- data/test/hexapdf/digital_signature/test_signature.rb +7 -0
- data/test/hexapdf/digital_signature/test_signatures.rb +8 -3
- data/test/hexapdf/font/cmap/test_writer.rb +73 -16
- data/test/hexapdf/font/test_true_type_wrapper.rb +17 -3
- data/test/hexapdf/layout/test_list_box.rb +7 -7
- data/test/hexapdf/layout/test_text_fragment.rb +3 -3
- data/test/hexapdf/layout/test_text_layouter.rb +4 -2
- data/test/hexapdf/task/test_merge_acro_form.rb +104 -0
- data/test/hexapdf/test_composer.rb +8 -0
- data/test/hexapdf/test_document.rb +9 -0
- data/test/hexapdf/test_parser.rb +23 -6
- data/test/hexapdf/test_writer.rb +10 -5
- data/test/hexapdf/test_xref_section.rb +15 -0
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +18 -18
- data/test/hexapdf/type/acro_form/test_form.rb +7 -3
- data/test/hexapdf/type/actions/test_launch.rb +6 -2
- data/test/hexapdf/type/test_font_type1.rb +5 -0
- data/test/hexapdf/type/test_form.rb +1 -1
- data/test/hexapdf/type/test_page.rb +7 -1
- data/test/hexapdf/utils/test_sorted_tree_node.rb +7 -6
- metadata +4 -2
@@ -0,0 +1,164 @@
|
|
1
|
+
# -*- encoding: utf-8; frozen_string_literal: true -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# This file is part of HexaPDF.
|
5
|
+
#
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
+
# Copyright (C) 2014-2024 Thomas Leitner
|
8
|
+
#
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
16
|
+
#
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
20
|
+
# License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
24
|
+
#
|
25
|
+
# The interactive user interfaces in modified source and object code
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
28
|
+
#
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
31
|
+
# is created or manipulated using HexaPDF.
|
32
|
+
#
|
33
|
+
# If the GNU Affero General Public License doesn't fit your need,
|
34
|
+
# commercial licenses are available at <https://gettalong.at/hexapdf/>.
|
35
|
+
#++
|
36
|
+
|
37
|
+
require 'hexapdf/serializer'
|
38
|
+
|
39
|
+
module HexaPDF
|
40
|
+
module Task
|
41
|
+
|
42
|
+
# Task for merging an AcroForm from one PDF into another.
|
43
|
+
#
|
44
|
+
# It takes care of
|
45
|
+
#
|
46
|
+
# * adding the fields to the main Type::AcroForm::Form dictionary,
|
47
|
+
# * adjusting the field names so that they are unique,
|
48
|
+
# * and merging the properties of the main AcroForm dictionary itself and adjusting field
|
49
|
+
# information appropriately.
|
50
|
+
#
|
51
|
+
# Note that the pages with the fields need to be imported already.
|
52
|
+
#
|
53
|
+
# The steps for using this task are:
|
54
|
+
#
|
55
|
+
# 1. Import the pages into the target document and add all imported pages to an array
|
56
|
+
# 2. Call this task using the created array of pages.
|
57
|
+
#
|
58
|
+
# Example:
|
59
|
+
#
|
60
|
+
# pages = doc.pages.map {|page| target.pages.add(target.import(page)) }
|
61
|
+
# target.task(:merge_acro_form, source: doc, pages: pages)
|
62
|
+
module MergeAcroForm
|
63
|
+
|
64
|
+
# Performs the necessary steps to merge the AcroForm fields from the +source+ into the target
|
65
|
+
# document +doc+.
|
66
|
+
#
|
67
|
+
# +source+::
|
68
|
+
# Specifies the source PDF document the information from which should be merged into the
|
69
|
+
# target document.
|
70
|
+
#
|
71
|
+
# +pages+::
|
72
|
+
# An array of pages that were imported from +source+ and contain the widgets of the fields
|
73
|
+
# that should be merged.
|
74
|
+
def self.call(doc, source:, pages:)
|
75
|
+
return unless source.acro_form
|
76
|
+
|
77
|
+
acro_form = doc.acro_form(create: true)
|
78
|
+
|
79
|
+
# Determine a unique name for root field and create root field
|
80
|
+
import_name = 'merged_' +
|
81
|
+
(acro_form.root_fields.select {|field| field[:T] =~ /\Amerged_\d+\z/ }.
|
82
|
+
map {|field| field[:T][/\d+/].to_i }.sort.last || 0).succ.to_s
|
83
|
+
root_field = doc.add({T: import_name, Kids: []})
|
84
|
+
acro_form.root_fields << root_field
|
85
|
+
|
86
|
+
# Merge the main AcroForm dictionary
|
87
|
+
font_name_mapping = merge_form_dictionary(acro_form, source.acro_form, root_field)
|
88
|
+
font_name_re = font_name_mapping.keys.map {|name| Regexp.escape(name) }.join('|')
|
89
|
+
root_field[:DA] && root_field[:DA].sub!(font_name_re, font_name_mapping)
|
90
|
+
|
91
|
+
# Process all field widgets of the given pages
|
92
|
+
process_calculate_actions = false
|
93
|
+
signature_field_seen = false
|
94
|
+
pages.each do |page|
|
95
|
+
page.each_annotation do |widget|
|
96
|
+
next unless widget[:Subtype] == :Widget
|
97
|
+
field = widget.form_field
|
98
|
+
|
99
|
+
# Correct the font name in the default appearance string
|
100
|
+
widget[:DA] && widget[:DA].sub!(font_name_re, font_name_mapping)
|
101
|
+
field[:DA] && field[:DA].sub!(font_name_re, font_name_mapping)
|
102
|
+
|
103
|
+
process_calculate_actions = true if field[:AA]&.[](:C)
|
104
|
+
signature_field_seen = true if field.field_type == :Sig
|
105
|
+
|
106
|
+
# Add to the root field
|
107
|
+
field = field[:Parent] while field[:Parent]
|
108
|
+
if field != root_field
|
109
|
+
field[:Parent] = root_field
|
110
|
+
root_field[:Kids] << field
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Update calculation JavaScript actions with changed field names
|
116
|
+
fix_calculate_actions(acro_form, source.acro_form, import_name) if process_calculate_actions
|
117
|
+
|
118
|
+
# Update signature flags if necessary
|
119
|
+
if signature_field_seen && source.acro_form.signature_flag?(:signatures_exist)
|
120
|
+
acro_form.signature_flag(:signatures_exist)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Merges the AcroForm +source_form+ into the +target_form+ and returns a mapping of old font
|
125
|
+
# names to new ones.
|
126
|
+
def self.merge_form_dictionary(target_form, source_form, root_field)
|
127
|
+
target_resources = target_form.default_resources
|
128
|
+
font_name_mapping = {}
|
129
|
+
serializer = HexaPDF::Serializer.new
|
130
|
+
|
131
|
+
source_form.default_resources[:Font].each do |font_name, value|
|
132
|
+
new_name = target_resources.add_font(target_form.document.import(value))
|
133
|
+
font_name_mapping[serializer.serialize(font_name)] = serializer.serialize(new_name)
|
134
|
+
end
|
135
|
+
|
136
|
+
root_field[:DA] = target_form.document.import(source_form[:DA])
|
137
|
+
root_field[:Q] = target_form.document.import(source_form[:Q])
|
138
|
+
|
139
|
+
font_name_mapping
|
140
|
+
end
|
141
|
+
|
142
|
+
# Fixes the calculate actions listed in the /CO entry of the main AcroForm dictionary to use
|
143
|
+
# the new names of the fields.
|
144
|
+
def self.fix_calculate_actions(acro_form, source_form, import_name)
|
145
|
+
if source_form[:CO]
|
146
|
+
acro_form[:CO] ||= []
|
147
|
+
acro_form[:CO].value.concat(acro_form.document.import(source_form[:CO]).value)
|
148
|
+
acro_form[:CO].each do |field|
|
149
|
+
next unless (action = field[:AA]&.[](:C))
|
150
|
+
action[:JS].gsub!(/"(.*?)"/) do |match|
|
151
|
+
if source_form.field_by_name($1)
|
152
|
+
"\"#{import_name}.#{$1}\""
|
153
|
+
else
|
154
|
+
match
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
end
|
data/lib/hexapdf/task.rb
CHANGED
data/lib/hexapdf/tokenizer.rb
CHANGED
@@ -144,6 +144,8 @@ module HexaPDF
|
|
144
144
|
elsif byte == 93 # ]
|
145
145
|
@ss.pos += 1
|
146
146
|
TOKEN_ARRAY_END
|
147
|
+
elsif byte == 41 # )
|
148
|
+
raise HexaPDF::MalformedPDFError.new("Delimiter ')' found at invalid position", pos: pos)
|
147
149
|
elsif byte == 123 || byte == 125 # { }
|
148
150
|
Token.new(@ss.get_byte)
|
149
151
|
elsif byte == 37 # %
|
@@ -81,6 +81,7 @@ module HexaPDF
|
|
81
81
|
define_field :CO, type: PDFArray, version: '1.3'
|
82
82
|
define_field :DR, type: :XXResources
|
83
83
|
define_field :DA, type: String
|
84
|
+
define_field :Q, type: Integer
|
84
85
|
define_field :XFA, type: [Stream, PDFArray], version: '1.5'
|
85
86
|
|
86
87
|
bit_field(:signature_flags, {signatures_exist: 0, append_only: 1},
|
@@ -182,29 +183,18 @@ module HexaPDF
|
|
182
183
|
# The optional keyword arguments allow setting often used properties of the field:
|
183
184
|
#
|
184
185
|
# +font+::
|
185
|
-
# The font that should be used for the text of the field. If
|
186
|
-
#
|
187
|
-
#
|
188
|
-
# If no font is set on the text field, the default font properties of the AcroForm form
|
189
|
-
# are used. Note that field specific or form specific font properties have to be
|
190
|
-
# set. Otherwise there might be problems when creating a visual appearance with other
|
191
|
-
# PDF libraries/viewers.
|
192
|
-
#
|
193
|
-
# If HexaPDF is used to create a visual appearance of the field value and neither field
|
194
|
-
# specific nor form specific font properties are available, the configuration option
|
195
|
-
# 'acro_form.fallback_default_appearance' defines whether and which field specific font
|
196
|
-
# properties are set and used.
|
186
|
+
# The font that should be used for the text of the field. If not specified, it
|
187
|
+
# defaults to Helvetica.
|
197
188
|
#
|
198
189
|
# +font_options+::
|
199
|
-
# A hash with font options like :variant that should be used.
|
190
|
+
# A hash with font options like :variant that should be used. If not specified, it
|
191
|
+
# defaults to the empty hash.
|
200
192
|
#
|
201
193
|
# +font_size+::
|
202
|
-
# The font size that should be used. If
|
203
|
-
# specified but +font_size+ isn't, font size defaults to 0 (= auto-sizing).
|
194
|
+
# The font size that should be used. If not specified, it defaults to 0 (= auto-sizing).
|
204
195
|
#
|
205
196
|
# +font_color+::
|
206
|
-
# The font color that should be used. If
|
207
|
-
# specified but +font_color+ isn't, font color defaults to 0 (i.e. black).
|
197
|
+
# The font color that should be used. If not specified, it defaults to 0 (i.e. black).
|
208
198
|
#
|
209
199
|
# +align+::
|
210
200
|
# The alignment of the text, either :left, :center or :right.
|
@@ -445,8 +435,7 @@ module HexaPDF
|
|
445
435
|
|
446
436
|
# Returns the dictionary containing the default resources for form field appearance streams.
|
447
437
|
def default_resources
|
448
|
-
self[:DR] ||= document.wrap({
|
449
|
-
type: :XXResources)
|
438
|
+
self[:DR] ||= document.wrap({}, type: :XXResources)
|
450
439
|
end
|
451
440
|
|
452
441
|
# Sets the global default appearance string using the provided values or the default values
|
@@ -532,7 +521,7 @@ module HexaPDF
|
|
532
521
|
field = Field.wrap(document, field)
|
533
522
|
next unless field && (calculation_action = field[:AA]&.[](:C))
|
534
523
|
result = JavaScriptActions.calculate(self, calculation_action)
|
535
|
-
field.
|
524
|
+
field.field_value = result if result
|
536
525
|
end
|
537
526
|
end
|
538
527
|
|
@@ -566,13 +555,11 @@ module HexaPDF
|
|
566
555
|
# Applies the given variable field properties to the field.
|
567
556
|
def apply_variable_text_properties(field, font: nil, font_options: nil, font_size: nil,
|
568
557
|
font_color: nil, align: nil)
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
end
|
575
|
-
field.text_alignment(align) if align
|
558
|
+
field.set_default_appearance_string(font: font || 'Helvetica',
|
559
|
+
font_options: font_options || {},
|
560
|
+
font_size: font_size || 0,
|
561
|
+
font_color: font_color || 0)
|
562
|
+
field.text_alignment(align || :left)
|
576
563
|
end
|
577
564
|
|
578
565
|
def perform_validation # :nodoc:
|
@@ -62,8 +62,10 @@ module HexaPDF
|
|
62
62
|
|
63
63
|
define_field :Type, type: Symbol, default: type
|
64
64
|
define_field :Action, type: Symbol, required: true,
|
65
|
-
|
65
|
+
allowed_values: [:All, :Include, :Exclude]
|
66
66
|
define_field :Fields, type: PDFArray
|
67
|
+
define_field :P, type: Numeric, version: '2.0',
|
68
|
+
allowed_values: [1, 2, 3]
|
67
69
|
|
68
70
|
private
|
69
71
|
|
@@ -83,8 +85,8 @@ module HexaPDF
|
|
83
85
|
# If a flag is set it means that the associated entry is a required constraint. Otherwise it
|
84
86
|
# is optional.
|
85
87
|
#
|
86
|
-
# The available flags are: filter, sub_filter, v, reasons, legal_attestation, add_rev_info
|
87
|
-
# and
|
88
|
+
# The available flags are: filter, sub_filter, v, reasons, legal_attestation, add_rev_info,
|
89
|
+
# digest_method, lock_document and appearance_filter.
|
88
90
|
#
|
89
91
|
# See: PDF2.0 s12.7.5.5
|
90
92
|
class SeedValueDictionary < Dictionary
|
@@ -98,13 +100,16 @@ module HexaPDF
|
|
98
100
|
define_field :Filter, type: Symbol
|
99
101
|
define_field :SubFilter, type: PDFArray
|
100
102
|
define_field :DigestMethod, type: PDFArray, version: '1.7'
|
101
|
-
define_field :V, type:
|
103
|
+
define_field :V, type: Integer
|
102
104
|
define_field :Cert, type: :SVCert
|
103
105
|
define_field :Reasons, type: PDFArray
|
104
106
|
define_field :MDP, type: Dictionary, version: '1.6'
|
105
107
|
define_field :TimeStamp, type: Dictionary, version: '1.6'
|
106
108
|
define_field :LegalAttestation, type: PDFArray, version: '1.6'
|
107
109
|
define_field :AddRevInfo, type: Boolean, version: '1.7'
|
110
|
+
define_field :LockDocument, type: Symbol, version: '2.0',
|
111
|
+
allowed_values: [:true, :false, :auto]
|
112
|
+
define_field :AppearanceFilter, type: String, version: '2.0'
|
108
113
|
|
109
114
|
##
|
110
115
|
# :method: flags
|
@@ -130,7 +135,8 @@ module HexaPDF
|
|
130
135
|
# all prior flags will be cleared.
|
131
136
|
#
|
132
137
|
bit_field(:flags, {filter: 0, sub_filter: 1, v: 2, reasons: 3, legal_attestation: 4,
|
133
|
-
add_rev_info: 5, digest_method: 6
|
138
|
+
add_rev_info: 5, digest_method: 6, lock_document: 7,
|
139
|
+
appearance_filter: 8},
|
134
140
|
lister: "flags", getter: "flagged?", setter: "flag", unsetter: "unflag",
|
135
141
|
value_getter: "self[:Ff]", value_setter: "self[:Ff]")
|
136
142
|
|
@@ -155,12 +161,16 @@ module HexaPDF
|
|
155
161
|
define_field :Type, type: Symbol, default: type
|
156
162
|
define_field :Ff, type: Integer, default: 0
|
157
163
|
define_field :Subject, type: PDFArray
|
164
|
+
define_field :SignaturePolicyOID, type: String, version: '2.0'
|
165
|
+
define_field :SignaturePolicyHashValue, type: String, version: '2.0'
|
166
|
+
define_field :SignaturePolicyHashAlgorithm, type: Symbol, version: '2.0'
|
167
|
+
define_field :SignaturePolicyCommitmentType, type: PDFArray, version: '2.0'
|
158
168
|
define_field :SubjectDN, type: PDFArray, version: '1.7'
|
159
169
|
define_field :KeyUsage, type: PDFArray, version: '1.7'
|
160
170
|
define_field :Issuer, type: PDFArray
|
161
171
|
define_field :OID, type: PDFArray
|
162
172
|
define_field :URL, type: String
|
163
|
-
define_field :URLType, type: Symbol, default: :Browser
|
173
|
+
define_field :URLType, type: Symbol, default: :Browser, version: '1.7'
|
164
174
|
|
165
175
|
##
|
166
176
|
# :method: flags
|
@@ -51,7 +51,7 @@ module HexaPDF
|
|
51
51
|
# See: PDF2.0 s12.7.4.3
|
52
52
|
class VariableTextField < Field
|
53
53
|
|
54
|
-
define_field :DA, type:
|
54
|
+
define_field :DA, type: PDFByteString
|
55
55
|
define_field :Q, type: Integer, default: 0, allowed_values: [0, 1, 2]
|
56
56
|
define_field :DS, type: String, version: '1.5'
|
57
57
|
define_field :RV, type: [String, Stream], version: '1.5'
|
@@ -48,6 +48,7 @@ module HexaPDF
|
|
48
48
|
define_field :S, type: Symbol, required: true, default: :GoToR
|
49
49
|
define_field :F, type: :Filespec, required: true
|
50
50
|
define_field :D, type: [Symbol, PDFByteString, PDFArray], required: true
|
51
|
+
define_field :SD, type: PDFArray, version: '2.0'
|
51
52
|
define_field :NewWindow, type: Boolean, version: '1.2'
|
52
53
|
|
53
54
|
end
|
@@ -60,13 +60,17 @@ module HexaPDF
|
|
60
60
|
define_field :S, type: Symbol, required: true, default: :Launch
|
61
61
|
define_field :F, type: :Filespec
|
62
62
|
define_field :Win, type: :XXLaunchActionWinParameters
|
63
|
+
define_field :Mac, type: ::Object, version: '2.0'
|
64
|
+
define_field :Unix, type: ::Object, version: '2.0'
|
63
65
|
define_field :NewWindow, type: Boolean, version: '1.2'
|
64
66
|
|
65
67
|
private
|
66
68
|
|
67
69
|
def perform_validation #:nodoc:
|
68
70
|
super
|
69
|
-
|
71
|
+
unless key?(:Win) || key?(:Mac) || key?(:Unix) || key?(:F)
|
72
|
+
yield("Launch action key /F required if /Win, /Mac and /Unix are absent")
|
73
|
+
end
|
70
74
|
end
|
71
75
|
|
72
76
|
end
|
@@ -123,7 +123,7 @@ module HexaPDF
|
|
123
123
|
define_field :Contents, type: String
|
124
124
|
define_field :P, type: Dictionary, version: '1.3'
|
125
125
|
define_field :NM, type: String, version: '1.4'
|
126
|
-
define_field :M, type: PDFDate, version: '1.1'
|
126
|
+
define_field :M, type: [PDFDate, String], version: '1.1'
|
127
127
|
define_field :F, type: Integer, default: 0, version: '1.1'
|
128
128
|
define_field :AP, type: :XXAppearanceDictionary, version: '1.2'
|
129
129
|
define_field :AS, type: Symbol, version: '1.2'
|
@@ -131,6 +131,11 @@ module HexaPDF
|
|
131
131
|
define_field :C, type: PDFArray, version: '1.1'
|
132
132
|
define_field :StructParent, type: Integer, version: '1.3'
|
133
133
|
define_field :OC, type: Dictionary, version: '1.5'
|
134
|
+
define_field :AF, type: PDFArray, version: '2.0'
|
135
|
+
define_field :ca, type: Numeric, default: 1.0, version: '2.0'
|
136
|
+
define_field :CA, type: Numeric, default: 1.0, version: '2.0'
|
137
|
+
define_field :BM, type: Symbol, version: '2.0'
|
138
|
+
define_field :Lang, type: String, version: '2.0'
|
134
139
|
|
135
140
|
##
|
136
141
|
# :method: flags
|
@@ -46,6 +46,19 @@ module HexaPDF
|
|
46
46
|
# See: PDF2.0 s12.5.6.2, HexaPDF::Type::Annotation
|
47
47
|
class MarkupAnnotation < Annotation
|
48
48
|
|
49
|
+
# External data dictionary used by some markup annotation types.
|
50
|
+
#
|
51
|
+
# See: PDF2.0 s12.5.6.2
|
52
|
+
class ExData < Dictionary
|
53
|
+
|
54
|
+
define_type :ExData
|
55
|
+
|
56
|
+
define_field :Type, type: Symbol, required: true, default: type
|
57
|
+
define_field :Subtype, type: Symbol, required: true,
|
58
|
+
allowed_values: [:Markup3D, :'3DM', :MarkupGeo]
|
59
|
+
|
60
|
+
end
|
61
|
+
|
49
62
|
define_field :T, type: String, version: '1.1'
|
50
63
|
define_field :Popup, type: :Annot, version: '1.3'
|
51
64
|
define_field :CA, type: Numeric, default: 1.0, version: '1.4'
|
@@ -56,7 +69,7 @@ module HexaPDF
|
|
56
69
|
define_field :RT, type: Symbol, default: :R, allowed_values: [:R, :Group],
|
57
70
|
version: '1.6'
|
58
71
|
define_field :IT, type: Symbol, version: '1.6'
|
59
|
-
define_field :ExData, type:
|
72
|
+
define_field :ExData, type: :ExData, version: '1.7'
|
60
73
|
|
61
74
|
private
|
62
75
|
|
data/lib/hexapdf/type/catalog.rb
CHANGED
@@ -84,6 +84,9 @@ module HexaPDF
|
|
84
84
|
define_field :Requirements, type: PDFArray, version: '1.7'
|
85
85
|
define_field :Collection, type: Dictionary, version: '1.7'
|
86
86
|
define_field :NeedsRendering, type: Boolean, version: '1.7'
|
87
|
+
define_field :DSS, type: Dictionary, version: '2.0'
|
88
|
+
define_field :AF, type: PDFArray, version: '2.0'
|
89
|
+
define_field :DPartRoot, type: Dictionary, version: '2.0'
|
87
90
|
|
88
91
|
# Returns +true+ since catalog objects must always be indirect.
|
89
92
|
def must_be_indirect?
|
@@ -61,13 +61,16 @@ module HexaPDF
|
|
61
61
|
|
62
62
|
DEFAULT_WIDTH = 1000 # :nodoc:
|
63
63
|
|
64
|
+
define_field :Subtype, type: Symbol, required: true,
|
65
|
+
allowed_values: [:CIDFontType0, :CIDFontType2]
|
64
66
|
define_field :BaseFont, type: Symbol, required: true
|
65
67
|
define_field :CIDSystemInfo, type: :XXCIDSystemInfo, required: true
|
66
|
-
define_field :FontDescriptor, type: :FontDescriptor,
|
68
|
+
define_field :FontDescriptor, type: :FontDescriptor, required: true
|
67
69
|
define_field :DW, type: Integer, default: DEFAULT_WIDTH
|
68
70
|
define_field :W, type: PDFArray
|
69
71
|
define_field :DW2, type: PDFArray, default: [880, -1100]
|
70
72
|
define_field :W2, type: PDFArray
|
73
|
+
define_field :CIDToGIDMap, type: [Symbol, Stream]
|
71
74
|
|
72
75
|
# Returns the unscaled width of the given CID in glyph units, or 0 if the width for the CID is
|
73
76
|
# missing.
|
@@ -78,19 +78,22 @@ module HexaPDF
|
|
78
78
|
|
79
79
|
define_type :Filespec
|
80
80
|
|
81
|
-
define_field :Type,
|
82
|
-
define_field :FS,
|
83
|
-
define_field :F,
|
84
|
-
define_field :UF,
|
85
|
-
define_field :DOS,
|
86
|
-
define_field :Mac,
|
87
|
-
define_field :Unix,
|
88
|
-
define_field :ID,
|
89
|
-
define_field :V,
|
90
|
-
define_field :EF,
|
91
|
-
define_field :RF,
|
92
|
-
define_field :Desc,
|
93
|
-
define_field :CI,
|
81
|
+
define_field :Type, type: Symbol, default: type, required: true
|
82
|
+
define_field :FS, type: Symbol
|
83
|
+
define_field :F, type: PDFByteString
|
84
|
+
define_field :UF, type: String, version: '1.7'
|
85
|
+
define_field :DOS, type: PDFByteString
|
86
|
+
define_field :Mac, type: PDFByteString
|
87
|
+
define_field :Unix, type: PDFByteString
|
88
|
+
define_field :ID, type: PDFArray
|
89
|
+
define_field :V, type: Boolean, version: '1.2'
|
90
|
+
define_field :EF, type: :XXFilespecEFDictionary, version: '1.7'
|
91
|
+
define_field :RF, type: Dictionary, version: '1.3'
|
92
|
+
define_field :Desc, type: String, version: '1.6'
|
93
|
+
define_field :CI, type: Dictionary, version: '1.7'
|
94
|
+
define_field :Thumb, type: Stream, version: '2.0'
|
95
|
+
define_field :EP, type: Dictionary, version: '2.0'
|
96
|
+
define_field :AF, type: Symbol, version: '2.0', default: :Unspecified
|
94
97
|
|
95
98
|
# Returns +true+ if this file specification references an URL and not a file.
|
96
99
|
def url?
|
@@ -114,7 +117,7 @@ module HexaPDF
|
|
114
117
|
|
115
118
|
# Sets the file specification string to the given filename.
|
116
119
|
#
|
117
|
-
# Since the /Unix, /Mac and /DOS fields are
|
120
|
+
# Since the /Unix, /Mac and /DOS fields are deprecated, only the /F and /UF fields are set.
|
118
121
|
def path=(filename)
|
119
122
|
self[:UF] = filename
|
120
123
|
self[:F] = filename.b
|
@@ -57,7 +57,7 @@ module HexaPDF
|
|
57
57
|
define_field :FontStretch, type: Symbol, version: '1.5',
|
58
58
|
allowed_values: [:UltraCondensed, :ExtraCondensed, :Condensed, :SemiCondensed,
|
59
59
|
:Normal, :SemiExpanded, :Expanded, :ExtraExpanded, :UltraExpanded]
|
60
|
-
define_field :FontWeight, type:
|
60
|
+
define_field :FontWeight, type: Integer, version: '1.5' # also see validation
|
61
61
|
define_field :Flags, type: Integer, required: true
|
62
62
|
define_field :FontBBox, type: Rectangle
|
63
63
|
define_field :ItalicAngle, type: Numeric, required: true
|
@@ -76,6 +76,7 @@ module HexaPDF
|
|
76
76
|
define_field :FontFile3, type: Stream, version: '1.2'
|
77
77
|
define_field :CharSet, type: [PDFByteString, String], version: '1.1'
|
78
78
|
|
79
|
+
# From PDF2.0 s9.8.3.1
|
79
80
|
define_field :Style, type: Dictionary
|
80
81
|
define_field :Lang, type: Symbol, version: '1.5'
|
81
82
|
define_field :FD, type: Dictionary
|
@@ -98,13 +99,13 @@ module HexaPDF
|
|
98
99
|
|
99
100
|
font_weight = self[:FontWeight]
|
100
101
|
if font_weight && !ALLOWED_FONT_WEIGHTS.include?(font_weight)
|
101
|
-
yield("Field FontWeight
|
102
|
+
yield("Field FontWeight contains the disallowed value #{font_weight}", true)
|
102
103
|
delete(:FontWeight)
|
103
104
|
end
|
104
105
|
|
105
106
|
descent = self[:Descent]
|
106
107
|
if descent && descent > 0
|
107
|
-
yield("The /Descent value needs to be
|
108
|
+
yield("The /Descent value needs to be zero or negative", true)
|
108
109
|
self[:Descent] = -descent
|
109
110
|
end
|
110
111
|
end
|
@@ -47,10 +47,12 @@ module HexaPDF
|
|
47
47
|
# See: PDF2.0 s9.6
|
48
48
|
class FontSimple < Font
|
49
49
|
|
50
|
+
# Only the common fields are defined here, the rest in FontType1, FontType3, FontTrueType
|
51
|
+
define_field :Name, type: Symbol
|
50
52
|
define_field :FirstChar, type: Integer
|
51
53
|
define_field :LastChar, type: Integer
|
52
54
|
define_field :Widths, type: PDFArray
|
53
|
-
define_field :FontDescriptor, type: :FontDescriptor
|
55
|
+
define_field :FontDescriptor, type: :FontDescriptor
|
54
56
|
define_field :Encoding, type: [Dictionary, Symbol]
|
55
57
|
|
56
58
|
# Returns the font descriptor. May be +nil+ for a standard 14 font.
|
@@ -48,7 +48,7 @@ module HexaPDF
|
|
48
48
|
# Composite fonts also allow for vertical writing mode and support TrueType as well as OpenType
|
49
49
|
# fonts.
|
50
50
|
#
|
51
|
-
# See: PDF2.0 s9.7
|
51
|
+
# See: PDF2.0 s9.7, s9.7.6.1
|
52
52
|
class FontType0 < Font
|
53
53
|
|
54
54
|
define_field :Subtype, type: Symbol, required: true, default: :Type0
|
@@ -170,6 +170,8 @@ module HexaPDF
|
|
170
170
|
end
|
171
171
|
end
|
172
172
|
|
173
|
+
PREDEFINED_ENCODING = [:MacRomanEncoding, :MacExpertEncoding, :WinAnsiEncoding] #:nodoc:
|
174
|
+
|
173
175
|
# Validates the Type1 font dictionary.
|
174
176
|
def perform_validation
|
175
177
|
std_font = StandardFonts.standard_font?(self[:BaseFont])
|
@@ -178,6 +180,11 @@ module HexaPDF
|
|
178
180
|
if !std_font && self[:FontDescriptor].nil?
|
179
181
|
yield("Required field FontDescriptor is not set", false)
|
180
182
|
end
|
183
|
+
|
184
|
+
encoding = self[:Encoding]
|
185
|
+
if encoding.kind_of?(Symbol) && !PREDEFINED_ENCODING.include?(encoding)
|
186
|
+
yield("The /Encoding value '#{encoding}' is invalid", false)
|
187
|
+
end
|
181
188
|
end
|
182
189
|
|
183
190
|
end
|
@@ -49,7 +49,6 @@ module HexaPDF
|
|
49
49
|
class FontType3 < FontSimple
|
50
50
|
|
51
51
|
define_field :Subtype, type: Symbol, required: true, default: :Type3
|
52
|
-
define_field :Name, type: Symbol
|
53
52
|
define_field :FontBBox, type: Rectangle, required: true
|
54
53
|
define_field :FontMatrix, type: PDFArray, required: true
|
55
54
|
define_field :CharProcs, type: Dictionary, required: true
|
data/lib/hexapdf/type/form.rb
CHANGED
@@ -89,6 +89,10 @@ module HexaPDF
|
|
89
89
|
define_field :StructParents, type: Integer, version: '1.3'
|
90
90
|
define_field :OPI, type: Dictionary, version: '1.2'
|
91
91
|
define_field :OC, type: Dictionary, version: '1.5'
|
92
|
+
define_field :Name, type: Symbol
|
93
|
+
define_field :AF, type: PDFArray, version: '2.0'
|
94
|
+
define_field :Measure, type: Dictionary, version: '2.0'
|
95
|
+
define_field :PtData, type: Dictionary, version: '2.0'
|
92
96
|
|
93
97
|
# Returns the path to the PDF file that was used when creating the form object.
|
94
98
|
#
|
@@ -131,8 +135,7 @@ module HexaPDF
|
|
131
135
|
|
132
136
|
# Returns the resource dictionary which is automatically created if it doesn't exist.
|
133
137
|
def resources
|
134
|
-
self[:Resources] ||= document.wrap({
|
135
|
-
type: :XXResources)
|
138
|
+
self[:Resources] ||= document.wrap({}, type: :XXResources)
|
136
139
|
end
|
137
140
|
|
138
141
|
# Processes the content stream of the form XObject with the given processor object.
|
@@ -58,10 +58,10 @@ module HexaPDF
|
|
58
58
|
define_field :ML, type: Numeric, version: "1.3"
|
59
59
|
define_field :D, type: PDFArray, version: "1.3"
|
60
60
|
define_field :RI, type: Symbol, version: "1.3",
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
61
|
+
allowed_values: [HexaPDF::Content::RenderingIntent::ABSOLUTE_COLORIMETRIC,
|
62
|
+
HexaPDF::Content::RenderingIntent::RELATIVE_COLORIMETRIC,
|
63
|
+
HexaPDF::Content::RenderingIntent::SATURATION,
|
64
|
+
HexaPDF::Content::RenderingIntent::PERCEPTUAL]
|
65
65
|
define_field :OP, type: Boolean
|
66
66
|
define_field :op, type: Boolean, version: "1.3"
|
67
67
|
define_field :OPM, type: Integer, version: "1.3"
|
@@ -82,6 +82,9 @@ module HexaPDF
|
|
82
82
|
define_field :ca, type: Numeric, version: "1.4"
|
83
83
|
define_field :AIS, type: Boolean, version: "1.4"
|
84
84
|
define_field :TK, type: Boolean, version: "1.4"
|
85
|
+
define_field :UseBlackPtComp, type: Symbol, version: "2.0",
|
86
|
+
allowed_values: [:OFF, :ON, :Default]
|
87
|
+
define_field :HTO, type: PDFArray, version: "2.0"
|
85
88
|
|
86
89
|
end
|
87
90
|
|