hexapdf 0.47.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -16
- 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 +1 -1
- 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/version.rb +1 -1
- 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 +7 -0
- data/test/hexapdf/test_writer.rb +8 -3
- 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
- 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
|
|