hexapdf 1.1.1 → 1.3.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 +79 -0
- data/README.md +1 -1
- data/lib/hexapdf/cli/command.rb +63 -63
- data/lib/hexapdf/cli/inspect.rb +14 -5
- data/lib/hexapdf/cli/modify.rb +0 -1
- data/lib/hexapdf/cli/optimize.rb +5 -5
- data/lib/hexapdf/composer.rb +14 -0
- data/lib/hexapdf/configuration.rb +26 -0
- data/lib/hexapdf/content/graphics_state.rb +1 -1
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +1 -1
- data/lib/hexapdf/document/annotations.rb +173 -0
- data/lib/hexapdf/document/layout.rb +45 -6
- data/lib/hexapdf/document.rb +28 -7
- data/lib/hexapdf/error.rb +11 -3
- data/lib/hexapdf/font/true_type/subsetter.rb +15 -2
- data/lib/hexapdf/font/true_type_wrapper.rb +1 -0
- data/lib/hexapdf/font/type1_wrapper.rb +1 -0
- data/lib/hexapdf/layout/style.rb +101 -7
- data/lib/hexapdf/object.rb +2 -2
- data/lib/hexapdf/pdf_array.rb +25 -3
- data/lib/hexapdf/tokenizer.rb +4 -1
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +57 -8
- data/lib/hexapdf/type/acro_form/field.rb +1 -0
- data/lib/hexapdf/type/acro_form/form.rb +7 -6
- data/lib/hexapdf/type/acro_form/java_script_actions.rb +9 -2
- data/lib/hexapdf/type/acro_form/text_field.rb +9 -2
- data/lib/hexapdf/type/annotation.rb +71 -1
- data/lib/hexapdf/type/annotations/appearance_generator.rb +348 -0
- data/lib/hexapdf/type/annotations/border_effect.rb +99 -0
- data/lib/hexapdf/type/annotations/border_styling.rb +160 -0
- data/lib/hexapdf/type/annotations/circle.rb +65 -0
- data/lib/hexapdf/type/annotations/interior_color.rb +84 -0
- data/lib/hexapdf/type/annotations/line.rb +490 -0
- data/lib/hexapdf/type/annotations/square.rb +65 -0
- data/lib/hexapdf/type/annotations/square_circle.rb +77 -0
- data/lib/hexapdf/type/annotations/widget.rb +52 -116
- data/lib/hexapdf/type/annotations.rb +8 -0
- data/lib/hexapdf/type/form.rb +2 -2
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/writer.rb +0 -1
- data/lib/hexapdf/xref_section.rb +7 -4
- data/test/hexapdf/content/test_graphics_state.rb +2 -3
- data/test/hexapdf/content/test_operator.rb +4 -5
- data/test/hexapdf/digital_signature/test_cms_handler.rb +7 -8
- data/test/hexapdf/digital_signature/test_handler.rb +2 -3
- data/test/hexapdf/digital_signature/test_pkcs1_handler.rb +1 -2
- data/test/hexapdf/document/test_annotations.rb +55 -0
- data/test/hexapdf/document/test_layout.rb +24 -2
- data/test/hexapdf/font/test_true_type_wrapper.rb +7 -0
- data/test/hexapdf/font/test_type1_wrapper.rb +7 -0
- data/test/hexapdf/font/true_type/test_subsetter.rb +10 -0
- data/test/hexapdf/layout/test_style.rb +27 -2
- data/test/hexapdf/task/test_optimize.rb +1 -1
- data/test/hexapdf/test_composer.rb +7 -0
- data/test/hexapdf/test_document.rb +11 -3
- data/test/hexapdf/test_object.rb +1 -1
- data/test/hexapdf/test_pdf_array.rb +36 -3
- data/test/hexapdf/test_stream.rb +1 -2
- data/test/hexapdf/test_xref_section.rb +1 -1
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +78 -3
- data/test/hexapdf/type/acro_form/test_button_field.rb +7 -6
- data/test/hexapdf/type/acro_form/test_field.rb +5 -0
- data/test/hexapdf/type/acro_form/test_form.rb +17 -1
- data/test/hexapdf/type/acro_form/test_java_script_actions.rb +21 -0
- data/test/hexapdf/type/acro_form/test_text_field.rb +7 -1
- data/test/hexapdf/type/annotations/test_appearance_generator.rb +482 -0
- data/test/hexapdf/type/annotations/test_border_effect.rb +59 -0
- data/test/hexapdf/type/annotations/test_border_styling.rb +114 -0
- data/test/hexapdf/type/annotations/test_interior_color.rb +37 -0
- data/test/hexapdf/type/annotations/test_line.rb +169 -0
- data/test/hexapdf/type/annotations/test_widget.rb +35 -81
- data/test/hexapdf/type/test_annotation.rb +55 -0
- data/test/hexapdf/type/test_form.rb +6 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0e469ae650b98b48c88b662dab27cb405b676c706639c8c1cf358d6aefc8f53
|
4
|
+
data.tar.gz: d170526233e1e9aa37403c1bd8d2aa38697641c1b4fb4d4a5f6d8f02f299585b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd18408ed2c2474e3395bf59b3a0281cb23005d16bf7d5b9d93f673dfa131fc215f342018d0cdce2de053db85c000a68c28a76ad980b0432b1a159bd51b1ed0c
|
7
|
+
data.tar.gz: c58b13ed27c980bb9670b9521a12b1640fc3960aea1188f6135951cfd1503a28e7633cb3f6be8c63d478d64a88e0bbdc9b84bdbc982aa3ec000aeac1a8627597
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,82 @@
|
|
1
|
+
## 1.3.0 - 2025-04-23
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* [HexaPDF::Type::Annotations::Square] for rectangle annotations as well as
|
6
|
+
[HexaPDF::Document::Annotations#create_rectangle]
|
7
|
+
* [HexaPDF::Type::Annotations::Circle] for ellipse annotations as well as
|
8
|
+
[HexaPDF::Document::Annotations#create_ellipse]
|
9
|
+
* Basic appearance generation for push button fields
|
10
|
+
* [HexaPDF::Type::Annotation::BorderEffect] type class
|
11
|
+
* [HexaPDF::Type::Annotations::BorderEffect] module that provides convenience
|
12
|
+
access to the border effect dictionary
|
13
|
+
* [HexaPDF::Document::Layout#style?] and [HexaPDF::Composer#style?] for checking
|
14
|
+
whether a given style (name) exists
|
15
|
+
* [HexaPDF::Layout::Style#each_property] for iterating over all set properties
|
16
|
+
* [HexaPDF::Layout::Style#merge] for merging another style instance
|
17
|
+
* [HexaPDF::Layout::Style#box_options] for specifying box initialization options
|
18
|
+
* [HexaPDF::Layout::Style#font_bold] and [HexaPDF::Layout::Style#font_italic]
|
19
|
+
for setting bold and/or italic variants independently of the font name
|
20
|
+
* [HexaPDF::PDFArray#map!] for mapping elements in-place
|
21
|
+
* [HexaPDF::PDFArray#compact!] for removing `nil` elements
|
22
|
+
|
23
|
+
### Changed
|
24
|
+
|
25
|
+
* **Breaking change**: [HexaPDF::Type::Annotations::Widget::MarkerStyle::new]
|
26
|
+
got a new positional argument
|
27
|
+
* [HexaPDF::Type::Annotations::Widget#marker_style] to allow setting and
|
28
|
+
retrieving the font for push buttons
|
29
|
+
* Extracted `#interior_color` from [HexaPDF::Type::Annotations::Line] into
|
30
|
+
[HexaPDF::Type::Annotations::InteriorColor]
|
31
|
+
* CLI command `hexapdf inspect` to support decoding Form XObject streams
|
32
|
+
* [HexaPDF::Layout::Style#line_spacing] to accept a `LineSpacing` object when
|
33
|
+
setting the value
|
34
|
+
|
35
|
+
### Fixed
|
36
|
+
|
37
|
+
* Text extraction with macOS Preview due a bug in Preview
|
38
|
+
* [HexaPDF::PDFArray#reject!] to work according to documented method signature
|
39
|
+
* [HexaPDF::Type::AcroForm::Field#create_widget] to ensure the proper type
|
40
|
+
class is stored in the document in case an embedded widget is extracted
|
41
|
+
* [HexaPDF::Type::AcroForm::Form] validation to ensure that all field objects in
|
42
|
+
the field hierarchy are using a field type class
|
43
|
+
* [HexaPDF::Type::AcroForm::Form] validation to delete merged fields
|
44
|
+
|
45
|
+
|
46
|
+
## 1.2.0 - 2025-02-10
|
47
|
+
|
48
|
+
### Added
|
49
|
+
|
50
|
+
* **Breaking change**: Argument `compact` to [HexaPDF::Document#write] to
|
51
|
+
automatically run the 'compact' optimization task
|
52
|
+
* [HexaPDF::Document::Annotations], accessible via
|
53
|
+
[HexaPDF::Document#annotations], as convenience interface for working with
|
54
|
+
annotations
|
55
|
+
* [HexaPDF::Type::Annotations::AppearanceGenerator] as central class for
|
56
|
+
generating appearance streams
|
57
|
+
* [HexaPDF::Type::Annotations::Line] for line annotations
|
58
|
+
* [HexaPDF::Type::Annotation#opacity] for setting the opacity values when
|
59
|
+
regenerating the appearance stream
|
60
|
+
* [HexaPDF::Type::Annotation#contents] for setting the text of the annotation
|
61
|
+
* Configuration option 'acro_form.text_field.on_max_len_exceeded' to allow
|
62
|
+
custom handling of too long values
|
63
|
+
|
64
|
+
### Changed
|
65
|
+
|
66
|
+
* **Breaking change**: Extracted `#border_style` and associated data class from
|
67
|
+
[HexaPDF::Type::Annotations::Widget] into
|
68
|
+
[HexaPDF::Type::Annotations::BorderStyling]
|
69
|
+
* [HexaPDF::Type::Form#canvas] to allow getting the canvas without the initial
|
70
|
+
translation
|
71
|
+
|
72
|
+
### Fixed
|
73
|
+
|
74
|
+
* AcroForm Javascript actions to gracefully handle the special values infinity
|
75
|
+
and NaN
|
76
|
+
* Type1 and TrueType font wrappers to handle the case where fonts are first
|
77
|
+
added and later deleted
|
78
|
+
|
79
|
+
|
1
80
|
## 1.1.1 - 2025-01-08
|
2
81
|
|
3
82
|
### Fixed
|
data/README.md
CHANGED
@@ -82,7 +82,7 @@ canvas.text("Hello World!", at: [20, 400])
|
|
82
82
|
doc.write("hello-world.pdf")
|
83
83
|
~~~
|
84
84
|
|
85
|
-
For detailed information have a look at the [HexaPDF website][website] where you will the API
|
85
|
+
For detailed information have a look at the [HexaPDF website][website] where you will find the API
|
86
86
|
documentation, example code and more.
|
87
87
|
|
88
88
|
It is recommend to use the HTML API documentation provided by the HexaPDF website as it is enhanced
|
data/lib/hexapdf/cli/command.rb
CHANGED
@@ -35,7 +35,6 @@
|
|
35
35
|
#++
|
36
36
|
|
37
37
|
require 'io/console'
|
38
|
-
require 'ostruct'
|
39
38
|
require 'cmdparse'
|
40
39
|
require 'hexapdf/document'
|
41
40
|
require 'hexapdf/font/true_type'
|
@@ -68,21 +67,22 @@ module HexaPDF
|
|
68
67
|
|
69
68
|
def initialize(*args, **kwargs, &block) #:nodoc:
|
70
69
|
super
|
71
|
-
@out_options =
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
70
|
+
@out_options = {
|
71
|
+
compact: true,
|
72
|
+
compress_pages: false,
|
73
|
+
object_streams: :preserve,
|
74
|
+
xref_streams: :preserve,
|
75
|
+
streams: :preserve,
|
76
|
+
optimize_fonts: false,
|
77
|
+
prune_page_resources: false,
|
78
|
+
encryption: :preserve,
|
79
|
+
enc_user_pwd: nil,
|
80
|
+
enc_owner_pwd: nil,
|
81
|
+
enc_key_length: 128,
|
82
|
+
enc_algorithm: :aes,
|
83
|
+
enc_force_v4: false,
|
84
|
+
enc_permissions: [],
|
85
|
+
}
|
86
86
|
end
|
87
87
|
|
88
88
|
protected
|
@@ -163,7 +163,7 @@ module HexaPDF
|
|
163
163
|
if command_parser.verbosity_info?
|
164
164
|
puts "Creating output document #{out_file}"
|
165
165
|
end
|
166
|
-
doc.write(out_file, validate: false, incremental: incremental)
|
166
|
+
doc.write(out_file, validate: false, compact: false, incremental: incremental)
|
167
167
|
end
|
168
168
|
end
|
169
169
|
|
@@ -183,35 +183,35 @@ module HexaPDF
|
|
183
183
|
options.separator("")
|
184
184
|
options.separator("Optimization options:")
|
185
185
|
options.on("--[no-]compact", "Delete unnecessary PDF objects (default: " \
|
186
|
-
"#{@out_options
|
187
|
-
@out_options
|
186
|
+
"#{@out_options[:compact]})") do |c|
|
187
|
+
@out_options[:compact] = c
|
188
188
|
end
|
189
189
|
options.on("--object-streams MODE", [:generate, :preserve, :delete],
|
190
190
|
"Handling of object streams (either generate, preserve or delete; " \
|
191
|
-
"default: #{@out_options
|
192
|
-
@out_options
|
191
|
+
"default: #{@out_options[:object_streams]})") do |os|
|
192
|
+
@out_options[:object_streams] = os
|
193
193
|
end
|
194
194
|
options.on("--xref-streams MODE", [:generate, :preserve, :delete],
|
195
195
|
"Handling of cross-reference streams (either generate, preserve or delete; " \
|
196
|
-
"default: #{@out_options
|
197
|
-
@out_options
|
196
|
+
"default: #{@out_options[:xref_streams]})") do |x|
|
197
|
+
@out_options[:xref_streams] = x
|
198
198
|
end
|
199
199
|
options.on("--streams MODE", [:compress, :preserve, :uncompress],
|
200
200
|
"Handling of stream data (either compress, preserve or uncompress; default: " \
|
201
|
-
"#{@out_options
|
202
|
-
@out_options
|
201
|
+
"#{@out_options[:streams]})") do |streams|
|
202
|
+
@out_options[:streams] = streams
|
203
203
|
end
|
204
204
|
options.on("--[no-]compress-pages", "Recompress page content streams (may take a long " \
|
205
|
-
"time; default: #{@out_options
|
206
|
-
@out_options
|
205
|
+
"time; default: #{@out_options[:compress_pages]})") do |c|
|
206
|
+
@out_options[:compress_pages] = c
|
207
207
|
end
|
208
208
|
options.on("--[no-]prune-page-resources", "Prunes unused objects from the page resources " \
|
209
|
-
"(may take a long time; default: #{@out_options
|
210
|
-
@out_options
|
209
|
+
"(may take a long time; default: #{@out_options[:prune_page_resources]})") do |c|
|
210
|
+
@out_options[:prune_page_resources] = c
|
211
211
|
end
|
212
212
|
options.on("--[no-]optimize-fonts", "Optimize embedded font files; " \
|
213
|
-
"default: #{@out_options
|
214
|
-
@out_options
|
213
|
+
"default: #{@out_options[:optimize_fonts]})") do |o|
|
214
|
+
@out_options[:optimize_fonts] = o
|
215
215
|
end
|
216
216
|
end
|
217
217
|
|
@@ -222,37 +222,37 @@ module HexaPDF
|
|
222
222
|
options.separator("")
|
223
223
|
options.separator("Encryption options:")
|
224
224
|
options.on("--decrypt", "Remove any encryption") do
|
225
|
-
@out_options
|
225
|
+
@out_options[:encryption] = :remove
|
226
226
|
end
|
227
227
|
options.on("--encrypt", "Encrypt the output file") do
|
228
|
-
@out_options
|
228
|
+
@out_options[:encryption] = :add
|
229
229
|
end
|
230
230
|
options.on("--owner-password PASSWORD", String, "The owner password to be set on the " \
|
231
231
|
"output file (use - for reading from standard input)") do |pwd|
|
232
|
-
@out_options
|
233
|
-
@out_options
|
232
|
+
@out_options[:encryption] = :add
|
233
|
+
@out_options[:enc_owner_pwd] = (pwd == '-' ? read_password("Owner password") : pwd)
|
234
234
|
end
|
235
235
|
options.on("--user-password PASSWORD", String, "The user password to be set on the " \
|
236
236
|
"output file (use - for reading from standard input)") do |pwd|
|
237
|
-
@out_options
|
238
|
-
@out_options
|
237
|
+
@out_options[:encryption] = :add
|
238
|
+
@out_options[:enc_user_pwd] = (pwd == '-' ? read_password("User password") : pwd)
|
239
239
|
end
|
240
240
|
options.on("--algorithm ALGORITHM", [:aes, :arc4],
|
241
241
|
"The encryption algorithm: aes or arc4 (default: " \
|
242
|
-
"#{@out_options
|
243
|
-
@out_options
|
244
|
-
@out_options
|
242
|
+
"#{@out_options[:enc_algorithm]})") do |a|
|
243
|
+
@out_options[:encryption] = :add
|
244
|
+
@out_options[:enc_algorithm] = a
|
245
245
|
end
|
246
246
|
options.on("--key-length BITS", Integer,
|
247
247
|
"The encryption key length in bits (default: " \
|
248
|
-
"#{@out_options
|
249
|
-
@out_options
|
250
|
-
@out_options
|
248
|
+
"#{@out_options[:enc_key_length]})") do |i|
|
249
|
+
@out_options[:encryption] = :add
|
250
|
+
@out_options[:enc_key_length] = i
|
251
251
|
end
|
252
252
|
options.on("--force-V4",
|
253
253
|
"Force use of encryption version 4 if key length=128 and algorithm=arc4") do
|
254
|
-
@out_options
|
255
|
-
@out_options
|
254
|
+
@out_options[:encryption] = :add
|
255
|
+
@out_options[:enc_force_v4] = true
|
256
256
|
end
|
257
257
|
syms = HexaPDF::Encryption::StandardSecurityHandler::Permissions::SYMBOL_TO_PERMISSION.keys
|
258
258
|
options.on("--permissions PERMS", Array,
|
@@ -264,8 +264,8 @@ module HexaPDF
|
|
264
264
|
end
|
265
265
|
perm.to_sym
|
266
266
|
end
|
267
|
-
@out_options
|
268
|
-
@out_options
|
267
|
+
@out_options[:encryption] = :add
|
268
|
+
@out_options[:enc_permissions] = perms
|
269
269
|
end
|
270
270
|
end
|
271
271
|
|
@@ -273,12 +273,12 @@ module HexaPDF
|
|
273
273
|
#
|
274
274
|
# See: #define_optimization_options
|
275
275
|
def apply_optimization_options(doc)
|
276
|
-
doc.task(:optimize, compact: @out_options
|
277
|
-
object_streams: @out_options
|
278
|
-
xref_streams: @out_options
|
279
|
-
compress_pages: @out_options
|
280
|
-
prune_page_resources: @out_options
|
281
|
-
if @out_options
|
276
|
+
doc.task(:optimize, compact: @out_options[:compact],
|
277
|
+
object_streams: @out_options[:object_streams],
|
278
|
+
xref_streams: @out_options[:xref_streams],
|
279
|
+
compress_pages: @out_options[:compress_pages],
|
280
|
+
prune_page_resources: @out_options[:prune_page_resources])
|
281
|
+
if @out_options[:streams] != :preserve || @out_options[:optimize_fonts]
|
282
282
|
doc.each do |obj|
|
283
283
|
optimize_stream(obj)
|
284
284
|
optimize_font(obj)
|
@@ -292,15 +292,15 @@ module HexaPDF
|
|
292
292
|
|
293
293
|
# Applies the chosen stream mode to the given object.
|
294
294
|
def optimize_stream(obj)
|
295
|
-
return if @out_options
|
295
|
+
return if @out_options[:streams] == :preserve || !obj.respond_to?(:set_filter) ||
|
296
296
|
Array(obj[:Filter]).any? {|f| IGNORED_FILTERS[f] }
|
297
297
|
|
298
|
-
obj.set_filter(@out_options
|
298
|
+
obj.set_filter(@out_options[:streams] == :compress ? :FlateDecode : nil)
|
299
299
|
end
|
300
300
|
|
301
301
|
# Optimize the object if it is a font object.
|
302
302
|
def optimize_font(obj)
|
303
|
-
return unless @out_options
|
303
|
+
return unless @out_options[:optimize_fonts] && obj.kind_of?(HexaPDF::Type::Font) &&
|
304
304
|
(obj[:Subtype] == :TrueType ||
|
305
305
|
(obj[:Subtype] == :Type0 && obj.descendant_font[:Subtype] == :CIDFontType2)) &&
|
306
306
|
obj.embedded?
|
@@ -319,14 +319,14 @@ module HexaPDF
|
|
319
319
|
#
|
320
320
|
# See: #define_encryption_options
|
321
321
|
def apply_encryption_options(doc)
|
322
|
-
case @out_options
|
322
|
+
case @out_options[:encryption]
|
323
323
|
when :add
|
324
|
-
doc.encrypt(algorithm: @out_options
|
325
|
-
key_length: @out_options
|
326
|
-
force_v4: @out_options
|
327
|
-
permissions: @out_options
|
328
|
-
owner_password: @out_options
|
329
|
-
user_password: @out_options
|
324
|
+
doc.encrypt(algorithm: @out_options[:enc_algorithm],
|
325
|
+
key_length: @out_options[:enc_key_length],
|
326
|
+
force_v4: @out_options[:enc_force_v4],
|
327
|
+
permissions: @out_options[:enc_permissions],
|
328
|
+
owner_password: @out_options[:enc_owner_pwd],
|
329
|
+
user_password: @out_options[:enc_user_pwd])
|
330
330
|
when :remove
|
331
331
|
doc.encrypt(name: nil)
|
332
332
|
end
|
data/lib/hexapdf/cli/inspect.rb
CHANGED
@@ -188,12 +188,20 @@ module HexaPDF
|
|
188
188
|
end
|
189
189
|
serialize(obj.value, recursive: true) if obj
|
190
190
|
|
191
|
-
when 's', 'stream', 'raw', 'raw-stream'
|
191
|
+
when 's', 'stream', 'raw', 'raw-stream', 'sd'
|
192
192
|
if (obj = pdf_object_from_string_reference(data.shift) rescue $stderr.puts($!.message)) &&
|
193
193
|
obj.kind_of?(HexaPDF::Stream)
|
194
|
-
|
195
|
-
|
196
|
-
|
194
|
+
if command == 'sd'
|
195
|
+
if obj.respond_to?(:process_contents)
|
196
|
+
obj.process_contents(ContentProcessor.new)
|
197
|
+
else
|
198
|
+
$stderr.puts("Error: The object is not a Form XObject or page")
|
199
|
+
end
|
200
|
+
else
|
201
|
+
source = (command.start_with?('raw') ? obj.stream_source : obj.stream_decoder)
|
202
|
+
while source.alive? && (stream_data = source.resume)
|
203
|
+
$stdout.write(stream_data)
|
204
|
+
end
|
197
205
|
end
|
198
206
|
elsif command_parser.verbosity_info?
|
199
207
|
$stderr.puts("Note: Object has no stream data")
|
@@ -396,7 +404,7 @@ module HexaPDF
|
|
396
404
|
io = @doc.revisions.parser.io
|
397
405
|
|
398
406
|
io.seek(0, IO::SEEK_END)
|
399
|
-
startxrefs = @doc.revisions.map {|rev| rev.trailer[:Prev] } <<
|
407
|
+
startxrefs = @doc.revisions.map {|rev| rev.trailer[:Prev].to_i } <<
|
400
408
|
@doc.revisions.parser.startxref_offset <<
|
401
409
|
io.pos
|
402
410
|
startxrefs.sort!
|
@@ -427,6 +435,7 @@ module HexaPDF
|
|
427
435
|
["OID[,GEN] | o[bject] OID[,GEN]", "Print object"],
|
428
436
|
["r[ecursive] OID[,GEN]", "Print object recursively"],
|
429
437
|
["s[tream] OID[,GEN]", "Print filtered stream"],
|
438
|
+
["sd OID[,GEN]", "Print the decoded stream of a Form XObject or page"],
|
430
439
|
["raw[-stream] OID[,GEN]", "Print raw stream"],
|
431
440
|
["rev[ision] [NUMBER]", "Print or extract revision"],
|
432
441
|
["x[ref] OID[,GEN]", "Print the cross-reference entry"],
|
data/lib/hexapdf/cli/modify.rb
CHANGED
data/lib/hexapdf/cli/optimize.rb
CHANGED
@@ -53,11 +53,11 @@ module HexaPDF
|
|
53
53
|
EOF
|
54
54
|
|
55
55
|
@password = nil
|
56
|
-
@out_options
|
57
|
-
@out_options
|
58
|
-
@out_options
|
59
|
-
@out_options
|
60
|
-
@out_options
|
56
|
+
@out_options[:compact] = true
|
57
|
+
@out_options[:xref_streams] = :generate
|
58
|
+
@out_options[:object_streams] = :generate
|
59
|
+
@out_options[:streams] = :compress
|
60
|
+
@out_options[:optimize_fonts] = true
|
61
61
|
|
62
62
|
options.on("--password PASSWORD", "-p", String,
|
63
63
|
"The password for decryption. Use - for reading from standard input.") do |pwd|
|
data/lib/hexapdf/composer.rb
CHANGED
@@ -261,6 +261,20 @@ module HexaPDF
|
|
261
261
|
@document.layout.style(name, base: base, **properties)
|
262
262
|
end
|
263
263
|
|
264
|
+
# Returns +true+ if a style with the given +name+ exists, else +false+.
|
265
|
+
#
|
266
|
+
# See HexaPDF::Document::Layout#style for details; this method is just a thin wrapper around
|
267
|
+
# that method.
|
268
|
+
#
|
269
|
+
# Example:
|
270
|
+
#
|
271
|
+
# composer.style(:header, font: 'Helvetica')
|
272
|
+
# composer.style?(:header) # => true
|
273
|
+
# composer.style?(:paragraph) # => false
|
274
|
+
def style?(name)
|
275
|
+
@document.layout.style?(name)
|
276
|
+
end
|
277
|
+
|
264
278
|
# :call-seq:
|
265
279
|
# composer.styles -> styles
|
266
280
|
# composer.styles(**mapping) -> styles
|
@@ -224,6 +224,21 @@ module HexaPDF
|
|
224
224
|
# acro_form.text_field.default_width::
|
225
225
|
# A number specifying the default width of AcroForm text fields which should be auto-sized.
|
226
226
|
#
|
227
|
+
# acro_form.text_field.on_max_len_exceeded::
|
228
|
+
# Callback hook when the value of a text field exceeds the set maximum length.
|
229
|
+
#
|
230
|
+
# The value needs to be an object that responds to \#call(field, value) where +field+ is the
|
231
|
+
# AcroForm text field on which the value is set and +value+ is the invalid value. The returned
|
232
|
+
# value is used instead of the invalid value.
|
233
|
+
#
|
234
|
+
# The default implementation raises an error.
|
235
|
+
#
|
236
|
+
# annotation.appearance_generator::
|
237
|
+
# The class that should be used for generating appearances for annotations. If the value is a
|
238
|
+
# String, it should contain the name of a constant to such a class.
|
239
|
+
#
|
240
|
+
# See HexaPDF::Type::Annotations::AppearanceGenerator
|
241
|
+
#
|
227
242
|
# debug::
|
228
243
|
# If set to +true+, enables debug output.
|
229
244
|
#
|
@@ -502,6 +517,10 @@ module HexaPDF
|
|
502
517
|
"#{field.concrete_field_type} field named '#{field.full_field_name}'"
|
503
518
|
end,
|
504
519
|
'acro_form.text_field.default_width' => 100,
|
520
|
+
'acro_form.text_field.on_max_len_exceeded' => proc do |field, value|
|
521
|
+
raise HexaPDF::Error, "Value exceeds maximum allowed length of #{field[:MaxLen]}"
|
522
|
+
end,
|
523
|
+
'annotation.appearance_generator' => 'HexaPDF::Type::Annotations::AppearanceGenerator',
|
505
524
|
'debug' => false,
|
506
525
|
'document.auto_decrypt' => true,
|
507
526
|
'document.on_invalid_string' => proc do |str|
|
@@ -690,6 +709,7 @@ module HexaPDF
|
|
690
709
|
XXAcroFormField: 'HexaPDF::Type::AcroForm::Field',
|
691
710
|
XXAppearanceDictionary: 'HexaPDF::Type::Annotation::AppearanceDictionary',
|
692
711
|
Border: 'HexaPDF::Type::Annotation::Border',
|
712
|
+
XXBorderEffect: 'HexaPDF::Type::Annotation::BorderEffect',
|
693
713
|
SigFieldLock: 'HexaPDF::Type::AcroForm::SignatureField::LockDictionary',
|
694
714
|
SV: 'HexaPDF::Type::AcroForm::SignatureField::SeedValueDictionary',
|
695
715
|
SVCert: 'HexaPDF::Type::AcroForm::SignatureField::CertificateSeedValueDictionary',
|
@@ -746,6 +766,9 @@ module HexaPDF
|
|
746
766
|
Text: 'HexaPDF::Type::Annotations::Text',
|
747
767
|
Link: 'HexaPDF::Type::Annotations::Link',
|
748
768
|
Widget: 'HexaPDF::Type::Annotations::Widget',
|
769
|
+
Line: 'HexaPDF::Type::Annotations::Line',
|
770
|
+
Square: 'HexaPDF::Type::Annotations::Square',
|
771
|
+
Circle: 'HexaPDF::Type::Annotations::Circle',
|
749
772
|
XML: 'HexaPDF::Type::Metadata',
|
750
773
|
GTS_PDFX: 'HexaPDF::Type::OutputIntent',
|
751
774
|
GTS_PDFA1: 'HexaPDF::Type::OutputIntent',
|
@@ -774,6 +797,9 @@ module HexaPDF
|
|
774
797
|
Text: 'HexaPDF::Type::Annotations::Text',
|
775
798
|
Link: 'HexaPDF::Type::Annotations::Link',
|
776
799
|
Widget: 'HexaPDF::Type::Annotations::Widget',
|
800
|
+
Line: 'HexaPDF::Type::Annotations::Line',
|
801
|
+
Square: 'HexaPDF::Type::Annotations::Square',
|
802
|
+
Circle: 'HexaPDF::Type::Annotations::Circle',
|
777
803
|
},
|
778
804
|
XXAcroFormField: {
|
779
805
|
Tx: 'HexaPDF::Type::AcroForm::TextField',
|
@@ -255,7 +255,7 @@ module HexaPDF
|
|
255
255
|
array.inject(0) {|m, n| m < 0 ? m : (n < 0 ? -1 : m + n) } <= 0)
|
256
256
|
raise ArgumentError, "Invalid line dash pattern: #{array.inspect} #{phase.inspect}"
|
257
257
|
end
|
258
|
-
@array = array
|
258
|
+
@array = array
|
259
259
|
@phase = phase
|
260
260
|
end
|
261
261
|
|
@@ -108,7 +108,7 @@ module HexaPDF
|
|
108
108
|
# +type+::
|
109
109
|
# The type can either be :cms when creating standard PDF CMS signatures or :pades when
|
110
110
|
# creating PAdES compatible signatures. PAdES signatures are part of PDF 2.0.
|
111
|
-
def create(data, type: :cms, &block) # :yield:
|
111
|
+
def create(data, type: :cms, &block) # :yield: digest_algorithm, hashed_data
|
112
112
|
signed_attrs = create_signed_attrs(data, signing_time: (type == :cms))
|
113
113
|
signature = digest_and_sign_data(set(*signed_attrs.value).to_der, &block)
|
114
114
|
unsigned_attrs = create_unsigned_attrs(signature)
|