hexapdf 0.14.0 → 0.15.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 +106 -0
- data/lib/hexapdf/cli/form.rb +30 -8
- data/lib/hexapdf/configuration.rb +19 -4
- data/lib/hexapdf/dictionary.rb +8 -2
- data/lib/hexapdf/dictionary_fields.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +7 -2
- data/lib/hexapdf/error.rb +4 -3
- data/lib/hexapdf/filter.rb +1 -0
- data/lib/hexapdf/filter/crypt.rb +60 -0
- data/lib/hexapdf/font/true_type/subsetter.rb +16 -3
- data/lib/hexapdf/font/true_type/table/post.rb +15 -10
- data/lib/hexapdf/font/type1/afm_parser.rb +2 -1
- data/lib/hexapdf/font_loader/from_configuration.rb +2 -2
- data/lib/hexapdf/font_loader/from_file.rb +18 -8
- data/lib/hexapdf/importer.rb +3 -2
- data/lib/hexapdf/parser.rb +55 -15
- data/lib/hexapdf/pdf_array.rb +4 -1
- data/lib/hexapdf/revision.rb +16 -0
- data/lib/hexapdf/serializer.rb +43 -10
- data/lib/hexapdf/tokenizer.rb +44 -3
- data/lib/hexapdf/type/acro_form.rb +1 -0
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +32 -17
- data/lib/hexapdf/type/acro_form/button_field.rb +8 -4
- data/lib/hexapdf/type/acro_form/field.rb +1 -0
- data/lib/hexapdf/type/acro_form/form.rb +37 -0
- data/lib/hexapdf/type/acro_form/signature_field.rb +223 -0
- data/lib/hexapdf/type/annotation.rb +13 -9
- data/lib/hexapdf/type/annotations/widget.rb +3 -1
- data/lib/hexapdf/type/font_descriptor.rb +9 -2
- data/lib/hexapdf/type/page.rb +81 -0
- data/lib/hexapdf/type/resources.rb +4 -0
- data/lib/hexapdf/type/xref_stream.rb +7 -0
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/encryption/test_security_handler.rb +15 -0
- data/test/hexapdf/filter/test_crypt.rb +21 -0
- data/test/hexapdf/font/true_type/table/test_post.rb +1 -1
- data/test/hexapdf/font/true_type/test_subsetter.rb +10 -0
- data/test/hexapdf/font/type1/test_afm_parser.rb +5 -0
- data/test/hexapdf/font_loader/test_from_configuration.rb +7 -3
- data/test/hexapdf/font_loader/test_from_file.rb +7 -0
- data/test/hexapdf/test_dictionary.rb +5 -0
- data/test/hexapdf/test_dictionary_fields.rb +7 -0
- data/test/hexapdf/test_parser.rb +94 -2
- data/test/hexapdf/test_revision.rb +21 -0
- data/test/hexapdf/test_serializer.rb +10 -0
- data/test/hexapdf/test_tokenizer.rb +50 -0
- data/test/hexapdf/test_writer.rb +2 -2
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +24 -3
- data/test/hexapdf/type/acro_form/test_button_field.rb +13 -7
- data/test/hexapdf/type/acro_form/test_field.rb +5 -0
- data/test/hexapdf/type/acro_form/test_form.rb +46 -2
- data/test/hexapdf/type/acro_form/test_signature_field.rb +38 -0
- data/test/hexapdf/type/annotations/test_widget.rb +2 -0
- data/test/hexapdf/type/test_annotation.rb +20 -10
- data/test/hexapdf/type/test_font_descriptor.rb +7 -0
- data/test/hexapdf/type/test_page.rb +187 -49
- data/test/hexapdf/type/test_resources.rb +6 -0
- data/test/hexapdf/type/test_xref_stream.rb +7 -0
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bcd3bc77b70872416b1377b4fdf97804de083cf4d7213dfd200738fd8b2adae7
|
|
4
|
+
data.tar.gz: 53a8a850610a744570999cf56c656d6bd65c8ab691a5658b81172111bdd44804
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 54c99dbd44c4ae146496912f295982d47bb5ca297d4d2b76475c1f3151670068cd3be0c2dedee413b0a52e493383229bbd36d819ff2db2a9c04b377731cc107e
|
|
7
|
+
data.tar.gz: 8426e942709633b921f7a644e01b645d555cfcdecbdbd25bae03d0154cf07df3a3cd1f108adb16a8b449801c203014698a6b382133bbb63033a1d590351b61f7
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,109 @@
|
|
|
1
|
+
## 0.15.0 - 2021-04-12
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
* [HexaPDF::Type::Page#flatten_annotations] for flattening the annotations of a
|
|
6
|
+
page
|
|
7
|
+
* [HexaPDF::Type::AcroForm::Form#flatten] for flattening interactive forms
|
|
8
|
+
* [HexaPDF::Revision#update] for updating the stored wrapper class of a PDF
|
|
9
|
+
object
|
|
10
|
+
* [HexaPDF::Type::AcroForm::SignatureField] for working with AcroForm signature
|
|
11
|
+
fields
|
|
12
|
+
* Support for form field flattening to the `hexapdf form` CLI command
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
* **Breaking change**: Overhauled the interface for accessing appearances of
|
|
17
|
+
annotations to make it more convenient
|
|
18
|
+
* Validation of [HexaPDF::Type::FontDescriptor] to delete invalid `/FontWeight`
|
|
19
|
+
value
|
|
20
|
+
* [HexaPDF::MalformedPDFError#pos] an accessor instead of a reader and update
|
|
21
|
+
the exception message
|
|
22
|
+
* Configuration option 'acro_form.fallback_font' to allow a callable object for
|
|
23
|
+
more advanced fallback font handling
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
* [HexaPDF::Type::Annotations::Widget#background_color] to correctly handle
|
|
28
|
+
empty background color arrays
|
|
29
|
+
* [HexaPDF::Type::AcroForm::Field#delete_widget] to update the wrapper object
|
|
30
|
+
stored in the document in case the widget is embedded
|
|
31
|
+
* Processing of invalid PDF files containing a space,CR,LF combination after
|
|
32
|
+
the 'stream' keyword
|
|
33
|
+
* Cross-reference stream reconstruction with respect to detection of linearized
|
|
34
|
+
files
|
|
35
|
+
* Detection of existing appearances for AcroForm push button fields when
|
|
36
|
+
creating appearances
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## 0.14.4 - 2021-02-27
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
* Support for the Crypt filters
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
* [HexaPDF::MalformedPDFError] to make the `pos` argument optional
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
* Handling of invalid floating point numbers NaN, Inf and -Inf when serializing
|
|
52
|
+
* Processing of invalid PDF files containing NaN and Inf instead of numbers
|
|
53
|
+
* Bug in Type1 font AFM parser that occured if the file doesn't end with a new
|
|
54
|
+
line character
|
|
55
|
+
* Cross-reference table reconstruction to handle the case of an entry specifying
|
|
56
|
+
a non-existent indirect object
|
|
57
|
+
* Cross-reference table reconstruction to handle trailers specified by cross-
|
|
58
|
+
reference streams
|
|
59
|
+
* Cross-reference table reconstruction to use the set security handle for
|
|
60
|
+
decrypting indirect objects
|
|
61
|
+
* Parsing of cross-reference streams where data is missing
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
## 0.14.3 - 2021-02-16
|
|
65
|
+
|
|
66
|
+
### Fixed
|
|
67
|
+
|
|
68
|
+
* Bug in [HexaPDF::Font::TrueType::Subsetter#use_glyph] which lead to corrupt
|
|
69
|
+
text output
|
|
70
|
+
* [HexaPDF::Serializer] to handle infinite recursion problem
|
|
71
|
+
* Cross-reference table reconstruction to avoid an O(n^2) performance problem
|
|
72
|
+
* [HexaPDF::Type::Resources] validation to handle an invalid `/ProcSet` entry
|
|
73
|
+
containing a single value instead of an array
|
|
74
|
+
* Processing of invalid PDF files missing a required value in appearance streams
|
|
75
|
+
* Processing of invalid empty arrays that should be rectangles by converting
|
|
76
|
+
them to PDF null objects
|
|
77
|
+
* Processing of invalid PDF files containing indirect objects with offset 0
|
|
78
|
+
* Processing of invalid PDF files containing a space/CR or space/LF combination
|
|
79
|
+
after the 'stream' keyword
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
## 0.14.2 - 2021-01-22
|
|
83
|
+
|
|
84
|
+
### Fixed
|
|
85
|
+
|
|
86
|
+
* [HexaPDF::Font::TrueType::Subsetter#use_glyph] to really avoid using subset
|
|
87
|
+
glyph ID 41 (`)`)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
## 0.14.1 - 2021-01-21
|
|
91
|
+
|
|
92
|
+
### Changed
|
|
93
|
+
|
|
94
|
+
* Validation message when checking for allowed values to include the invalid
|
|
95
|
+
object
|
|
96
|
+
* [HexaPDF::FontLoader::FromFile] to allow (re)using an existing font object
|
|
97
|
+
* [HexaPDF::Importer] internals to avoid problems with retained memory
|
|
98
|
+
|
|
99
|
+
### Fixed
|
|
100
|
+
|
|
101
|
+
* Parsing of invalid PDF files where whitespace is missing after the integer
|
|
102
|
+
value of an indirect object
|
|
103
|
+
* [HexaPDF::Dictionary] so that adding new key-value pairs during validation is
|
|
104
|
+
possible
|
|
105
|
+
|
|
106
|
+
|
|
1
107
|
## 0.14.0 - 2020-12-30
|
|
2
108
|
|
|
3
109
|
### Added
|
data/lib/hexapdf/cli/form.rb
CHANGED
|
@@ -52,18 +52,26 @@ module HexaPDF
|
|
|
52
52
|
If the the output file name is not given, all form fields are listed in page order. Use
|
|
53
53
|
the global --verbose option to show additional information like field type and location.
|
|
54
54
|
|
|
55
|
-
If the output file name is given, the fields can be
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
If the output file name is given, the fields can be filled out interactively, via a
|
|
56
|
+
template or just flattened by using the respective options. Form field flattening can also
|
|
57
|
+
be activated in addition to filling out the form. If neither --fill, --template nor
|
|
58
|
+
--flatten is specified, --fill is implied.
|
|
58
59
|
EOF
|
|
59
60
|
|
|
60
61
|
options.on("--password PASSWORD", "-p", String,
|
|
61
62
|
"The password for decryption. Use - for reading from standard input.") do |pwd|
|
|
62
63
|
@password = (pwd == '-' ? read_password : pwd)
|
|
63
64
|
end
|
|
65
|
+
options.on("--fill", "Fill out the form") do
|
|
66
|
+
@fill = true
|
|
67
|
+
end
|
|
64
68
|
options.on("--template TEMPLATE_FILE", "-t TEMPLATE_FILE",
|
|
65
|
-
"Use the template file for the field values") do |template|
|
|
69
|
+
"Use the template file for the field values (implies --fill)") do |template|
|
|
66
70
|
@template = template
|
|
71
|
+
@fill = true
|
|
72
|
+
end
|
|
73
|
+
options.on('--flatten', 'Flatten the form fields') do
|
|
74
|
+
@flatten = true
|
|
67
75
|
end
|
|
68
76
|
options.on("--[no-]viewer-override", "Let the PDF viewer override the visual " \
|
|
69
77
|
"appearance. Default: use setting from input PDF") do |need_appearances|
|
|
@@ -75,6 +83,8 @@ module HexaPDF
|
|
|
75
83
|
end
|
|
76
84
|
|
|
77
85
|
@password = nil
|
|
86
|
+
@fill = false
|
|
87
|
+
@flatten = false
|
|
78
88
|
@template = nil
|
|
79
89
|
@need_appearances = nil
|
|
80
90
|
@incremental = true
|
|
@@ -82,16 +92,28 @@ module HexaPDF
|
|
|
82
92
|
|
|
83
93
|
def execute(in_file, out_file = nil) #:nodoc:
|
|
84
94
|
maybe_raise_on_existing_file(out_file) if out_file
|
|
95
|
+
if (@fill || @flatten) && !out_file
|
|
96
|
+
raise "Output file missing"
|
|
97
|
+
end
|
|
85
98
|
with_document(in_file, password: @password, out_file: out_file,
|
|
86
99
|
incremental: @incremental) do |doc|
|
|
87
100
|
if !doc.acro_form
|
|
88
101
|
raise "This PDF doesn't contain an interactive form"
|
|
89
102
|
elsif out_file
|
|
90
103
|
doc.acro_form[:NeedAppearances] = @need_appearances unless @need_appearances.nil?
|
|
91
|
-
if @
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
104
|
+
if @fill || !@flatten
|
|
105
|
+
if @template
|
|
106
|
+
fill_form_with_template(doc)
|
|
107
|
+
else
|
|
108
|
+
fill_form(doc)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
if @flatten
|
|
112
|
+
unless doc.acro_form.flatten.empty?
|
|
113
|
+
$stderr.puts "Warning: Not all form fields could be flattened"
|
|
114
|
+
doc.catalog.delete(:AcroForm)
|
|
115
|
+
doc.delete(doc.acro_form)
|
|
116
|
+
end
|
|
95
117
|
end
|
|
96
118
|
else
|
|
97
119
|
list_form_fields(doc)
|
|
@@ -164,9 +164,20 @@ module HexaPDF
|
|
|
164
164
|
# acro_form.fallback_font::
|
|
165
165
|
# The font that should be used when a variable text field references a font that cannot be used.
|
|
166
166
|
#
|
|
167
|
-
# Can
|
|
168
|
-
#
|
|
169
|
-
#
|
|
167
|
+
# Can be one of the following:
|
|
168
|
+
#
|
|
169
|
+
# * The name of a font, like 'Helvetica'.
|
|
170
|
+
#
|
|
171
|
+
# * An array consisting of the font name and a hash of font options, like ['Helvetica',
|
|
172
|
+
# variant: :italic].
|
|
173
|
+
#
|
|
174
|
+
# * A callable object receiving the field and the font object (or +nil+ if no valid font object
|
|
175
|
+
# was found) and which has to return either a font name or an array consisting of the font
|
|
176
|
+
# name and a hash of font options. This way the response can be different depending on the
|
|
177
|
+
# original font and it would also allow e.g. modifying the configured fonts to add custom
|
|
178
|
+
# ones.
|
|
179
|
+
#
|
|
180
|
+
# If set to +nil+, the use of the fallback font is disabled.
|
|
170
181
|
#
|
|
171
182
|
# Default is 'Helvetica'.
|
|
172
183
|
#
|
|
@@ -393,7 +404,7 @@ module HexaPDF
|
|
|
393
404
|
DCTDecode: 'HexaPDF::Filter::PassThrough',
|
|
394
405
|
DCT: 'HexaPDF::Filter::PassThrough',
|
|
395
406
|
JPXDecode: 'HexaPDF::Filter::PassThrough',
|
|
396
|
-
Crypt:
|
|
407
|
+
Crypt: 'HexaPDF::Filter::Crypt',
|
|
397
408
|
Encryption: 'HexaPDF::Filter::Encryption',
|
|
398
409
|
},
|
|
399
410
|
'font.map' => {},
|
|
@@ -516,6 +527,9 @@ module HexaPDF
|
|
|
516
527
|
XXAcroFormField: 'HexaPDF::Type::AcroForm::Field',
|
|
517
528
|
XXAppearanceDictionary: 'HexaPDF::Type::Annotation::AppearanceDictionary',
|
|
518
529
|
Border: 'HexaPDF::Type::Annotation::Border',
|
|
530
|
+
SigFieldLock: 'HexaPDF::Type::AcroForm::SignatureField::LockDictionary',
|
|
531
|
+
SV: 'HexaPDF::Type::AcroForm::SignatureField::SeedValueDictionary',
|
|
532
|
+
SVCert: 'HexaPDF::Type::AcroForm::SignatureField::CertificateSeedValueDictionary',
|
|
519
533
|
},
|
|
520
534
|
'object.subtype_map' => {
|
|
521
535
|
nil => {
|
|
@@ -561,6 +575,7 @@ module HexaPDF
|
|
|
561
575
|
Tx: 'HexaPDF::Type::AcroForm::TextField',
|
|
562
576
|
Btn: 'HexaPDF::Type::AcroForm::ButtonField',
|
|
563
577
|
Ch: 'HexaPDF::Type::AcroForm::ChoiceField',
|
|
578
|
+
Sig: 'HexaPDF::Type::AcroForm::SignatureField',
|
|
564
579
|
},
|
|
565
580
|
})
|
|
566
581
|
|
data/lib/hexapdf/dictionary.rb
CHANGED
|
@@ -155,6 +155,12 @@ module HexaPDF
|
|
|
155
155
|
# available (see ::define_field).
|
|
156
156
|
#
|
|
157
157
|
# * Returns the default value if one is specified and no value is available.
|
|
158
|
+
#
|
|
159
|
+
# Note: If field information is available for the entry, a Hash or Array value will always be
|
|
160
|
+
# wrapped by Dictionary or PDFArray. Otherwise, the value will be returned as-is.
|
|
161
|
+
#
|
|
162
|
+
# Note: This method may throw a "can't add a new key into hash during iteration" error in
|
|
163
|
+
# certain cases because it potentially modifies the underlying hash!
|
|
158
164
|
def [](name)
|
|
159
165
|
field = self.class.field(name)
|
|
160
166
|
data = if key?(name)
|
|
@@ -255,7 +261,7 @@ module HexaPDF
|
|
|
255
261
|
|
|
256
262
|
# Iterates over all currently set fields and those that are required.
|
|
257
263
|
def each_set_key_or_required_field #:yields: name, field
|
|
258
|
-
value.
|
|
264
|
+
value.keys.each {|name| yield(name, self.class.field(name)) }
|
|
259
265
|
self.class.each_field do |name, field|
|
|
260
266
|
yield(name, field) if field.required? && !value.key?(name)
|
|
261
267
|
end
|
|
@@ -301,7 +307,7 @@ module HexaPDF
|
|
|
301
307
|
|
|
302
308
|
# Check the value of the field against the allowed values.
|
|
303
309
|
if field.allowed_values && !field.allowed_values.include?(obj)
|
|
304
|
-
yield("Field #{name} does not contain an allowed value")
|
|
310
|
+
yield("Field #{name} does not contain an allowed value: #{obj.inspect}")
|
|
305
311
|
end
|
|
306
312
|
|
|
307
313
|
# Check if field value needs to be (in)direct
|
|
@@ -344,7 +344,7 @@ module HexaPDF
|
|
|
344
344
|
# Wraps a given array in the Rectangle class. Otherwise returns +nil+.
|
|
345
345
|
def self.convert(data, _type, document)
|
|
346
346
|
return unless data.kind_of?(Array) || data.kind_of?(HexaPDF::PDFArray)
|
|
347
|
-
document.wrap(data, type: Rectangle)
|
|
347
|
+
data.empty? ? document.wrap(nil) : document.wrap(data, type: Rectangle)
|
|
348
348
|
end
|
|
349
349
|
|
|
350
350
|
end
|
|
@@ -268,7 +268,7 @@ module HexaPDF
|
|
|
268
268
|
str.replace(string_algorithm.decrypt(key, str))
|
|
269
269
|
end
|
|
270
270
|
|
|
271
|
-
if obj.kind_of?(HexaPDF::Stream)
|
|
271
|
+
if obj.kind_of?(HexaPDF::Stream) && obj.raw_stream.filter[0] != :Crypt
|
|
272
272
|
unless string_algorithm == stream_algorithm
|
|
273
273
|
key = object_key(obj.oid, obj.gen, stream_algorithm)
|
|
274
274
|
end
|
|
@@ -300,7 +300,12 @@ module HexaPDF
|
|
|
300
300
|
obj.raw_stream.key == key && obj.raw_stream.algorithm == stream_algorithm
|
|
301
301
|
obj.raw_stream.undecrypted_fiber
|
|
302
302
|
else
|
|
303
|
-
|
|
303
|
+
filter = obj[:Filter]
|
|
304
|
+
if filter == :Crypt || (filter.kind_of?(PDFArray) && filter[0] == :Crypt)
|
|
305
|
+
result
|
|
306
|
+
else
|
|
307
|
+
stream_algorithm.encryption_fiber(key, result)
|
|
308
|
+
end
|
|
304
309
|
end
|
|
305
310
|
end
|
|
306
311
|
|
data/lib/hexapdf/error.rb
CHANGED
|
@@ -43,12 +43,13 @@ module HexaPDF
|
|
|
43
43
|
class MalformedPDFError < Error
|
|
44
44
|
|
|
45
45
|
# The byte position in the PDF file where the error occured.
|
|
46
|
-
|
|
46
|
+
attr_accessor :pos
|
|
47
47
|
|
|
48
48
|
# Creates a new malformed PDF error object for the given exception message.
|
|
49
49
|
#
|
|
50
|
-
# The byte position where the error occured
|
|
51
|
-
|
|
50
|
+
# The byte position where the error occured can either be given via the +pos+ argument or later
|
|
51
|
+
# via the #pos accessor but must be set before the exception message is retrieved.
|
|
52
|
+
def initialize(message, pos: nil)
|
|
52
53
|
super(message)
|
|
53
54
|
@pos = pos
|
|
54
55
|
end
|
data/lib/hexapdf/filter.rb
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
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-2020 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/error'
|
|
38
|
+
|
|
39
|
+
module HexaPDF
|
|
40
|
+
module Filter
|
|
41
|
+
|
|
42
|
+
# This filter module implements the Crypt filter. The only supported part is using the Identity
|
|
43
|
+
# filter.
|
|
44
|
+
module Crypt
|
|
45
|
+
|
|
46
|
+
# See HexaPDF::Filter
|
|
47
|
+
def self.decoder(source, options)
|
|
48
|
+
if !options || !options.key?(:Name) || options[:Name] == :Identity
|
|
49
|
+
source
|
|
50
|
+
else
|
|
51
|
+
raise FilterError, "Handling of Crypt filters besides Identity is not implemented"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
singleton_class.send(:alias_method, :encoder, :decoder)
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -63,6 +63,16 @@ module HexaPDF
|
|
|
63
63
|
def use_glyph(glyph_id)
|
|
64
64
|
return @glyph_map[glyph_id] if @glyph_map.key?(glyph_id)
|
|
65
65
|
@last_id += 1
|
|
66
|
+
# Handle codes for ASCII characters \r (13), (, ) (40, 41) and \ (92) specially so that
|
|
67
|
+
# they never appear in the output (PDF serialization would need to escape them)
|
|
68
|
+
if @last_id == 13 || @last_id == 40 || @last_id == 92
|
|
69
|
+
@glyph_map[:"s#{@last_id}"] = @last_id
|
|
70
|
+
if @last_id == 40
|
|
71
|
+
@last_id += 1
|
|
72
|
+
@glyph_map[:"s#{@last_id}"] = @last_id
|
|
73
|
+
end
|
|
74
|
+
@last_id += 1
|
|
75
|
+
end
|
|
66
76
|
@glyph_map[glyph_id] = @last_id
|
|
67
77
|
end
|
|
68
78
|
|
|
@@ -107,7 +117,7 @@ module HexaPDF
|
|
|
107
117
|
locations = []
|
|
108
118
|
|
|
109
119
|
@glyph_map.each_key do |old_gid|
|
|
110
|
-
glyph = orig_glyf[old_gid]
|
|
120
|
+
glyph = orig_glyf[old_gid.kind_of?(Symbol) ? 0 : old_gid]
|
|
111
121
|
locations << table.size
|
|
112
122
|
data = glyph.raw_data
|
|
113
123
|
if glyph.compound?
|
|
@@ -134,7 +144,7 @@ module HexaPDF
|
|
|
134
144
|
hmtx = @font[:hmtx]
|
|
135
145
|
data = ''.b
|
|
136
146
|
@glyph_map.each_key do |old_gid|
|
|
137
|
-
metric = hmtx[old_gid]
|
|
147
|
+
metric = hmtx[old_gid.kind_of?(Symbol) ? 0 : old_gid]
|
|
138
148
|
data << [metric.advance_width, metric.left_side_bearing].pack('n2')
|
|
139
149
|
end
|
|
140
150
|
data
|
|
@@ -166,7 +176,10 @@ module HexaPDF
|
|
|
166
176
|
# Adds the components of compound glyphs to the subset.
|
|
167
177
|
def add_glyph_components
|
|
168
178
|
glyf = @font[:glyf]
|
|
169
|
-
@glyph_map.keys.each
|
|
179
|
+
@glyph_map.keys.each do |gid|
|
|
180
|
+
next if gid.kind_of?(Symbol)
|
|
181
|
+
glyf[gid].components&.each {|cgid| use_glyph(cgid) }
|
|
182
|
+
end
|
|
170
183
|
end
|
|
171
184
|
|
|
172
185
|
end
|
|
@@ -99,18 +99,23 @@ module HexaPDF
|
|
|
99
99
|
@max_mem_type42, @min_mem_type1, @max_mem_type1 = read_formatted(24, 's>2N5')
|
|
100
100
|
|
|
101
101
|
sub_table_length = directory_entry.length - 32
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
cur_pos = io.pos
|
|
103
|
+
@glyph_names = lambda do |glyph_id|
|
|
104
|
+
io.pos = cur_pos
|
|
105
|
+
@glyph_names = case @format
|
|
106
|
+
when 1 then Format1.parse(io, sub_table_length)
|
|
107
|
+
when 2 then Format2.parse(io, sub_table_length)
|
|
108
|
+
when 3 then Format3.parse(io, sub_table_length)
|
|
109
|
+
when 4 then Format4.parse(io, sub_table_length)
|
|
110
110
|
else
|
|
111
|
-
[]
|
|
111
|
+
if font.config['font.true_type.unknown_format'] == :raise
|
|
112
|
+
raise HexaPDF::Error, "Unsupported post table format: #{@format}"
|
|
113
|
+
else
|
|
114
|
+
[]
|
|
115
|
+
end
|
|
112
116
|
end
|
|
113
|
-
|
|
117
|
+
@glyph_names[glyph_id]
|
|
118
|
+
end
|
|
114
119
|
end
|
|
115
120
|
|
|
116
121
|
# 'post' table format 1
|