hexapdf 0.32.2 → 0.34.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +104 -1
- data/README.md +9 -0
- data/examples/002-graphics.rb +15 -17
- data/examples/003-arcs.rb +9 -9
- data/examples/009-text_layouter_alignment.rb +1 -1
- data/examples/010-text_layouter_inline_boxes.rb +2 -2
- data/examples/011-text_layouter_line_wrapping.rb +1 -1
- data/examples/012-text_layouter_styling.rb +7 -7
- data/examples/013-text_layouter_shapes.rb +1 -1
- data/examples/014-text_in_polygon.rb +1 -1
- data/examples/015-boxes.rb +8 -7
- data/examples/016-frame_automatic_box_placement.rb +2 -2
- data/examples/017-frame_text_flow.rb +2 -1
- data/examples/018-composer.rb +1 -1
- data/examples/020-column_box.rb +2 -1
- data/examples/025-table_box.rb +46 -0
- data/examples/026-optional_content.rb +55 -0
- data/examples/027-composer_optional_content.rb +83 -0
- data/lib/hexapdf/cli/command.rb +12 -3
- data/lib/hexapdf/cli/fonts.rb +1 -1
- data/lib/hexapdf/cli/form.rb +5 -5
- data/lib/hexapdf/cli/inspect.rb +5 -7
- data/lib/hexapdf/composer.rb +106 -53
- data/lib/hexapdf/configuration.rb +65 -40
- data/lib/hexapdf/content/canvas.rb +445 -267
- data/lib/hexapdf/content/color_space.rb +72 -25
- data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
- data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
- data/lib/hexapdf/content/graphic_object.rb +6 -7
- data/lib/hexapdf/content/graphics_state.rb +54 -45
- data/lib/hexapdf/content/operator.rb +54 -54
- data/lib/hexapdf/content/parser.rb +2 -2
- data/lib/hexapdf/content/processor.rb +15 -15
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/content.rb +5 -0
- data/lib/hexapdf/dictionary.rb +7 -5
- data/lib/hexapdf/dictionary_fields.rb +43 -16
- data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
- data/lib/hexapdf/digital_signature/handler.rb +1 -1
- data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
- data/lib/hexapdf/digital_signature/signature.rb +6 -6
- data/lib/hexapdf/digital_signature/signatures.rb +13 -12
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
- data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
- data/lib/hexapdf/digital_signature/signing.rb +4 -0
- data/lib/hexapdf/digital_signature/verification_result.rb +3 -4
- data/lib/hexapdf/digital_signature.rb +7 -2
- data/lib/hexapdf/document/destinations.rb +12 -11
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +1 -1
- data/lib/hexapdf/document/layout.rb +170 -39
- data/lib/hexapdf/document/pages.rb +4 -3
- data/lib/hexapdf/document.rb +96 -55
- data/lib/hexapdf/encryption/aes.rb +5 -5
- data/lib/hexapdf/encryption/arc4.rb +1 -1
- data/lib/hexapdf/encryption/fast_aes.rb +2 -2
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/identity.rb +1 -1
- data/lib/hexapdf/encryption/ruby_aes.rb +11 -21
- data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +31 -24
- data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
- data/lib/hexapdf/encryption.rb +7 -2
- data/lib/hexapdf/error.rb +18 -0
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/flate_decode.rb +1 -1
- data/lib/hexapdf/filter/lzw_decode.rb +1 -1
- data/lib/hexapdf/filter/pass_through.rb +1 -1
- data/lib/hexapdf/filter/predictor.rb +1 -1
- data/lib/hexapdf/filter/run_length_decode.rb +1 -1
- data/lib/hexapdf/filter.rb +55 -6
- data/lib/hexapdf/font/cmap/parser.rb +2 -2
- data/lib/hexapdf/font/cmap.rb +1 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
- data/lib/hexapdf/font/invalid_glyph.rb +3 -0
- data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
- data/lib/hexapdf/font/type1_wrapper.rb +19 -4
- data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
- data/lib/hexapdf/font_loader/from_file.rb +5 -5
- data/lib/hexapdf/font_loader/standard14.rb +3 -3
- data/lib/hexapdf/font_loader.rb +3 -0
- data/lib/hexapdf/image_loader/jpeg.rb +2 -2
- data/lib/hexapdf/image_loader/pdf.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +2 -2
- data/lib/hexapdf/image_loader.rb +1 -1
- data/lib/hexapdf/importer.rb +13 -0
- data/lib/hexapdf/layout/box.rb +32 -5
- data/lib/hexapdf/layout/box_fitter.rb +2 -2
- data/lib/hexapdf/layout/column_box.rb +20 -5
- data/lib/hexapdf/layout/frame.rb +53 -18
- data/lib/hexapdf/layout/image_box.rb +5 -0
- data/lib/hexapdf/layout/inline_box.rb +21 -9
- data/lib/hexapdf/layout/list_box.rb +50 -20
- data/lib/hexapdf/layout/page_style.rb +6 -5
- data/lib/hexapdf/layout/style.rb +64 -9
- data/lib/hexapdf/layout/table_box.rb +684 -0
- data/lib/hexapdf/layout/text_box.rb +12 -3
- data/lib/hexapdf/layout/text_fragment.rb +29 -3
- data/lib/hexapdf/layout/text_layouter.rb +32 -8
- data/lib/hexapdf/layout.rb +1 -0
- data/lib/hexapdf/name_tree_node.rb +1 -1
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/object.rb +18 -7
- data/lib/hexapdf/parser.rb +7 -7
- data/lib/hexapdf/pdf_array.rb +1 -1
- data/lib/hexapdf/rectangle.rb +1 -1
- data/lib/hexapdf/reference.rb +1 -1
- data/lib/hexapdf/revision.rb +1 -1
- data/lib/hexapdf/revisions.rb +3 -3
- data/lib/hexapdf/serializer.rb +15 -15
- data/lib/hexapdf/stream.rb +5 -4
- data/lib/hexapdf/tokenizer.rb +14 -14
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
- data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/field.rb +2 -2
- data/lib/hexapdf/type/acro_form/form.rb +1 -1
- data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
- data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
- data/lib/hexapdf/type/acro_form.rb +1 -1
- data/lib/hexapdf/type/action.rb +1 -1
- data/lib/hexapdf/type/actions/go_to.rb +1 -1
- data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
- data/lib/hexapdf/type/actions/launch.rb +1 -1
- data/lib/hexapdf/type/actions/set_ocg_state.rb +86 -0
- data/lib/hexapdf/type/actions/uri.rb +1 -1
- data/lib/hexapdf/type/actions.rb +2 -1
- data/lib/hexapdf/type/annotation.rb +3 -3
- data/lib/hexapdf/type/annotations/link.rb +1 -1
- data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
- data/lib/hexapdf/type/annotations/text.rb +2 -3
- data/lib/hexapdf/type/annotations/widget.rb +2 -2
- data/lib/hexapdf/type/annotations.rb +1 -1
- data/lib/hexapdf/type/catalog.rb +11 -2
- data/lib/hexapdf/type/cid_font.rb +18 -4
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +2 -2
- data/lib/hexapdf/type/font_descriptor.rb +1 -1
- data/lib/hexapdf/type/font_simple.rb +2 -2
- data/lib/hexapdf/type/font_type0.rb +3 -3
- data/lib/hexapdf/type/font_type3.rb +1 -1
- data/lib/hexapdf/type/form.rb +76 -6
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/type/icon_fit.rb +1 -1
- data/lib/hexapdf/type/image.rb +1 -1
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/mark_information.rb +1 -1
- data/lib/hexapdf/type/names.rb +2 -2
- data/lib/hexapdf/type/object_stream.rb +2 -1
- data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
- data/lib/hexapdf/type/optional_content_group.rb +370 -0
- data/lib/hexapdf/type/optional_content_membership.rb +63 -0
- data/lib/hexapdf/type/optional_content_properties.rb +158 -0
- data/lib/hexapdf/type/outline.rb +1 -1
- data/lib/hexapdf/type/outline_item.rb +1 -1
- data/lib/hexapdf/type/page.rb +46 -21
- data/lib/hexapdf/type/page_label.rb +5 -9
- data/lib/hexapdf/type/page_tree_node.rb +1 -1
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +2 -2
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +2 -2
- data/lib/hexapdf/type.rb +4 -0
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -2
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/writer.rb +4 -4
- data/lib/hexapdf/xref_section.rb +2 -2
- data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
- data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
- data/test/hexapdf/content/test_canvas.rb +49 -1
- data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
- data/test/hexapdf/document/test_files.rb +2 -2
- data/test/hexapdf/document/test_layout.rb +105 -2
- data/test/hexapdf/document/test_pages.rb +6 -6
- data/test/hexapdf/encryption/test_security_handler.rb +12 -11
- data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
- data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
- data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
- data/test/hexapdf/layout/test_box.rb +14 -5
- data/test/hexapdf/layout/test_column_box.rb +65 -21
- data/test/hexapdf/layout/test_frame.rb +27 -15
- data/test/hexapdf/layout/test_image_box.rb +4 -0
- data/test/hexapdf/layout/test_inline_box.rb +17 -3
- data/test/hexapdf/layout/test_list_box.rb +84 -33
- data/test/hexapdf/layout/test_page_style.rb +3 -2
- data/test/hexapdf/layout/test_style.rb +60 -0
- data/test/hexapdf/layout/test_table_box.rb +728 -0
- data/test/hexapdf/layout/test_text_box.rb +26 -0
- data/test/hexapdf/layout/test_text_fragment.rb +33 -0
- data/test/hexapdf/layout/test_text_layouter.rb +36 -5
- data/test/hexapdf/test_composer.rb +10 -0
- data/test/hexapdf/test_dictionary.rb +10 -0
- data/test/hexapdf/test_dictionary_fields.rb +4 -1
- data/test/hexapdf/test_document.rb +5 -0
- data/test/hexapdf/test_filter.rb +8 -0
- data/test/hexapdf/test_importer.rb +9 -0
- data/test/hexapdf/test_object.rb +16 -5
- data/test/hexapdf/test_stream.rb +7 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
- data/test/hexapdf/type/acro_form/test_form.rb +4 -3
- data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
- data/test/hexapdf/type/test_catalog.rb +11 -0
- data/test/hexapdf/type/test_form.rb +119 -0
- data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
- data/test/hexapdf/type/test_optional_content_group.rb +158 -0
- data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
- data/test/hexapdf/type/test_page.rb +20 -6
- metadata +28 -8
data/lib/hexapdf/tokenizer.rb
CHANGED
@@ -42,7 +42,7 @@ module HexaPDF
|
|
42
42
|
|
43
43
|
# Tokenizes the content of an IO object following the PDF rules.
|
44
44
|
#
|
45
|
-
# See:
|
45
|
+
# See: PDF2.0 s7.2
|
46
46
|
class Tokenizer
|
47
47
|
|
48
48
|
# Represents a keyword in a PDF file.
|
@@ -61,12 +61,12 @@ module HexaPDF
|
|
61
61
|
|
62
62
|
# Characters defined as whitespace.
|
63
63
|
#
|
64
|
-
# See:
|
64
|
+
# See: PDF2.0 s7.2.2
|
65
65
|
WHITESPACE = " \n\r\0\t\f"
|
66
66
|
|
67
67
|
# Characters defined as delimiters.
|
68
68
|
#
|
69
|
-
# See:
|
69
|
+
# See: PDF2.0 s7.2.2
|
70
70
|
DELIMITER = "()<>{}/[]%"
|
71
71
|
|
72
72
|
WHITESPACE_MULTI_RE = /[#{WHITESPACE}]+/ # :nodoc:
|
@@ -171,7 +171,7 @@ module HexaPDF
|
|
171
171
|
# If the +allow_end_array_token+ argument is +true+, the ']' token is permitted to facilitate
|
172
172
|
# the use of this method during array parsing.
|
173
173
|
#
|
174
|
-
# See:
|
174
|
+
# See: PDF2.0 s7.3
|
175
175
|
def next_object(allow_end_array_token: false, allow_keyword: false)
|
176
176
|
token = next_token
|
177
177
|
|
@@ -231,7 +231,7 @@ module HexaPDF
|
|
231
231
|
# If a problem is detected, yields to caller where the argument +recoverable+ is truthy if the
|
232
232
|
# problem is recoverable.
|
233
233
|
#
|
234
|
-
# See:
|
234
|
+
# See: PDF2.0 7.5.4
|
235
235
|
def next_xref_entry #:yield: recoverable
|
236
236
|
prepare_string_scanner(20)
|
237
237
|
if !@ss.skip(/(\d{10}) (\d{5}) ([nf])(?: \r| \n|\r\n|(\r\r|\r|\n))/) || @ss[4]
|
@@ -242,7 +242,7 @@ module HexaPDF
|
|
242
242
|
|
243
243
|
# Skips all whitespace at the current position.
|
244
244
|
#
|
245
|
-
# See:
|
245
|
+
# See: PDF2.0 s7.2.2
|
246
246
|
def skip_whitespace
|
247
247
|
prepare_string_scanner
|
248
248
|
prepare_string_scanner while @ss.skip(WHITESPACE_MULTI_RE)
|
@@ -268,7 +268,7 @@ module HexaPDF
|
|
268
268
|
|
269
269
|
# Parses the keyword at the current position.
|
270
270
|
#
|
271
|
-
# See:
|
271
|
+
# See: PDF2.0 s7.2
|
272
272
|
def parse_keyword
|
273
273
|
str = scan_until(WHITESPACE_OR_DELIMITER_RE) || @ss.scan(/.*/)
|
274
274
|
TOKEN_CACHE[str]
|
@@ -278,12 +278,12 @@ module HexaPDF
|
|
278
278
|
|
279
279
|
# Parses the number (integer or real) at the current position.
|
280
280
|
#
|
281
|
-
# See:
|
281
|
+
# See: PDF2.0 s7.3.3
|
282
282
|
def parse_number
|
283
283
|
val = scan_until(WHITESPACE_OR_DELIMITER_RE) || @ss.scan(/.*/)
|
284
284
|
if val.match?(/\A[+-]?\d++(?!\.)\z/)
|
285
285
|
tmp = val.to_i
|
286
|
-
# Handle object references, see
|
286
|
+
# Handle object references, see PDF2.0 s7.3.10
|
287
287
|
prepare_string_scanner(10)
|
288
288
|
if @ss.scan(REFERENCE_RE)
|
289
289
|
tmp = if tmp > 0
|
@@ -315,7 +315,7 @@ module HexaPDF
|
|
315
315
|
|
316
316
|
# Parses the literal string at the current position.
|
317
317
|
#
|
318
|
-
# See:
|
318
|
+
# See: PDF2.0 s7.3.4.2
|
319
319
|
def parse_literal_string
|
320
320
|
@ss.pos += 1
|
321
321
|
str = "".b
|
@@ -358,7 +358,7 @@ module HexaPDF
|
|
358
358
|
|
359
359
|
# Parses the hex string at the current position.
|
360
360
|
#
|
361
|
-
# See:
|
361
|
+
# See: PDF2.0 s7.3.4.3
|
362
362
|
def parse_hex_string
|
363
363
|
@ss.pos += 1
|
364
364
|
data = scan_until(/(?=>)/)
|
@@ -373,7 +373,7 @@ module HexaPDF
|
|
373
373
|
|
374
374
|
# Parses the name at the current position.
|
375
375
|
#
|
376
|
-
# See:
|
376
|
+
# See: PDF2.0 s7.3.5
|
377
377
|
def parse_name
|
378
378
|
@ss.pos += 1
|
379
379
|
str = scan_until(WHITESPACE_OR_DELIMITER_RE) || @ss.scan(/.*/)
|
@@ -389,7 +389,7 @@ module HexaPDF
|
|
389
389
|
#
|
390
390
|
# It is assumed that the initial '[' has already been scanned.
|
391
391
|
#
|
392
|
-
# See:
|
392
|
+
# See: PDF2.0 s7.3.6
|
393
393
|
def parse_array
|
394
394
|
result = []
|
395
395
|
while true
|
@@ -408,7 +408,7 @@ module HexaPDF
|
|
408
408
|
#
|
409
409
|
# It is assumed that the initial '<<' has already been scanned.
|
410
410
|
#
|
411
|
-
# See:
|
411
|
+
# See: PDF2.0 s7.3.7
|
412
412
|
def parse_dictionary
|
413
413
|
result = {}
|
414
414
|
while true
|
@@ -61,7 +61,7 @@ module HexaPDF
|
|
61
61
|
# By subclassing and overriding the necessary methods it is possible to define custom
|
62
62
|
# appearances.
|
63
63
|
#
|
64
|
-
# See:
|
64
|
+
# See: PDF2.0 s12.5.5, s12.7
|
65
65
|
class AppearanceGenerator
|
66
66
|
|
67
67
|
# Creates a new instance for the given +widget+.
|
@@ -200,7 +200,7 @@ module HexaPDF
|
|
200
200
|
def create_text_appearances
|
201
201
|
default_resources = @document.acro_form.default_resources
|
202
202
|
font, font_size, font_color = retrieve_font_information(default_resources)
|
203
|
-
style = HexaPDF::Layout::Style.new(font: font, fill_color: font_color)
|
203
|
+
style = HexaPDF::Layout::Style.new(font: font, font_size: font_size, fill_color: font_color)
|
204
204
|
border_style = @widget.border_style
|
205
205
|
padding = [1, border_style.width].max
|
206
206
|
|
@@ -226,8 +226,6 @@ module HexaPDF
|
|
226
226
|
|
227
227
|
canvas = form.canvas
|
228
228
|
apply_background_and_border(border_style, canvas)
|
229
|
-
style.font_size = calculate_font_size(font, font_size, height, border_style)
|
230
|
-
style.clear_cache
|
231
229
|
|
232
230
|
canvas.marked_content_sequence(:Tx) do
|
233
231
|
if @field.field_value || @field.concrete_field_type == :list_box
|
@@ -362,6 +360,7 @@ module HexaPDF
|
|
362
360
|
def draw_single_line_text(canvas, width, height, style, padding)
|
363
361
|
value, text_color = apply_javascript_formatting(@field.field_value)
|
364
362
|
style.fill_color = text_color if text_color
|
363
|
+
calculate_and_apply_font_size(value, style, width, height, padding)
|
365
364
|
fragment = HexaPDF::Layout::TextFragment.create(value, style)
|
366
365
|
|
367
366
|
if @field.concrete_field_type == :comb_text_field
|
@@ -431,6 +430,11 @@ module HexaPDF
|
|
431
430
|
|
432
431
|
# Draws the visible option items of the list box in the widget's rectangle.
|
433
432
|
def draw_list_box(canvas, width, height, style, padding)
|
433
|
+
if style.font_size == 0
|
434
|
+
style.font_size = 12 # Seems to be Adobe's default
|
435
|
+
style.clear_cache
|
436
|
+
end
|
437
|
+
|
434
438
|
option_items = @field.option_items
|
435
439
|
top_index = @field.list_box_top_index
|
436
440
|
items = [Layout::TextFragment.create(option_items[top_index..-1].join("\n"), style)]
|
@@ -475,24 +479,20 @@ module HexaPDF
|
|
475
479
|
[font, font_size, font_color]
|
476
480
|
end
|
477
481
|
|
478
|
-
# Calculates the font size for text fields based on the font
|
479
|
-
# appearance string, the annotation rectangle's height and
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
end
|
493
|
-
else
|
494
|
-
font_size
|
495
|
-
end
|
482
|
+
# Calculates the font size for single line text fields using auto-sizing, based on the font
|
483
|
+
# and font size of the default appearance string, the annotation rectangle's height and
|
484
|
+
# width and the given padding. The font size is then applied to the provided style object.
|
485
|
+
def calculate_and_apply_font_size(value, style, width, height, padding)
|
486
|
+
return if style.font_size != 0
|
487
|
+
|
488
|
+
font = style.font
|
489
|
+
unit_font_size = (font.wrapped_font.bounding_box[3] - font.wrapped_font.bounding_box[1]) *
|
490
|
+
font.scaling_factor / 1000.0
|
491
|
+
# The constant factor was found empirically by checking what Adobe Reader etc. do
|
492
|
+
style.font_size = (height - 2 * padding) / unit_font_size * 0.85
|
493
|
+
fragment = HexaPDF::Layout::TextFragment.create(value, style)
|
494
|
+
style.font_size = [style.font_size, style.font_size * (width - 4 * padding) / fragment.width].min
|
495
|
+
style.clear_cache
|
496
496
|
end
|
497
497
|
|
498
498
|
# Handles Javascript formatting routines for single-line text fields.
|
@@ -81,7 +81,7 @@ module HexaPDF
|
|
81
81
|
# :radios_in_unison:: A group of radio buttons with the same value for the on state will turn
|
82
82
|
# on or off in unison.
|
83
83
|
#
|
84
|
-
# See:
|
84
|
+
# See: PDF2.0 s12.7.4.2
|
85
85
|
class ButtonField < Field
|
86
86
|
|
87
87
|
define_type :XXAcroFormField
|
@@ -86,7 +86,7 @@ module HexaPDF
|
|
86
86
|
# to combination of the superclass value of the constant and the mapping of flag names to bit
|
87
87
|
# indices.
|
88
88
|
#
|
89
|
-
# See:
|
89
|
+
# See: PDF2.0 s12.7.4.1
|
90
90
|
class Field < Dictionary
|
91
91
|
|
92
92
|
# Provides a #value method for hash that returns self so that a Hash can be used
|
@@ -367,7 +367,7 @@ module HexaPDF
|
|
367
367
|
document.pages.each do |page|
|
368
368
|
if page.key?(:Annots) && (index = page[:Annots].index(self))
|
369
369
|
page[:Annots][index] = widget
|
370
|
-
break # Each annotation dictionary may only appear on one page, see
|
370
|
+
break # Each annotation dictionary may only appear on one page, see PDF2.0 12.5.2
|
371
371
|
end
|
372
372
|
end
|
373
373
|
widget
|
@@ -68,7 +68,7 @@ module HexaPDF
|
|
68
68
|
# HexaPDF uses the configuration option +acro_form.create_appearance_streams+ to determine
|
69
69
|
# whether appearances should automatically be generated.
|
70
70
|
#
|
71
|
-
# See:
|
71
|
+
# See: PDF2.0 s12.7.3, Field, HexaPDF::Type::Annotations::Widget
|
72
72
|
class Form < Dictionary
|
73
73
|
|
74
74
|
extend Utils::BitField
|
@@ -49,13 +49,13 @@ module HexaPDF
|
|
49
49
|
# If the signature should not be visible, the associated widget annotation should have zero
|
50
50
|
# width and height; and/or the 'hidden' or 'no_view' flags of the annotation should be set.
|
51
51
|
#
|
52
|
-
# See:
|
52
|
+
# See: PDF2.0 s12.7.5.5
|
53
53
|
class SignatureField < Field
|
54
54
|
|
55
55
|
# A signature field lock dictionary specifies a set of form fields that should be locked
|
56
56
|
# once the associated signature field is signed.
|
57
57
|
#
|
58
|
-
# See:
|
58
|
+
# See: PDF2.0 s12.7.5.5
|
59
59
|
class LockDictionary < Dictionary
|
60
60
|
|
61
61
|
define_type :SigFieldLock
|
@@ -86,7 +86,7 @@ module HexaPDF
|
|
86
86
|
# The available flags are: filter, sub_filter, v, reasons, legal_attestation, add_rev_info
|
87
87
|
# and digest_method.
|
88
88
|
#
|
89
|
-
# See:
|
89
|
+
# See: PDF2.0 s12.7.5.5
|
90
90
|
class SeedValueDictionary < Dictionary
|
91
91
|
|
92
92
|
extend Utils::BitField
|
@@ -145,7 +145,7 @@ module HexaPDF
|
|
145
145
|
#
|
146
146
|
# The available flags are: subject, issuer, oid, subject_dn, reserved, key_usage and url.
|
147
147
|
#
|
148
|
-
# See:
|
148
|
+
# See: PDF2.0 s12.7.5.5
|
149
149
|
class CertificateSeedValueDictionary < Dictionary
|
150
150
|
|
151
151
|
extend Utils::BitField
|
data/lib/hexapdf/type/action.rb
CHANGED
@@ -44,7 +44,7 @@ module HexaPDF
|
|
44
44
|
# Action dictionaries are used, for example, by annotations or outline items to specify the
|
45
45
|
# action that should be performed. Each action class should be defined under the Actions module.
|
46
46
|
#
|
47
|
-
# See:
|
47
|
+
# See: PDF2.0 s12.6
|
48
48
|
class Action < Dictionary
|
49
49
|
|
50
50
|
define_type :Action
|
@@ -42,7 +42,7 @@ module HexaPDF
|
|
42
42
|
|
43
43
|
# A Launch action dictionary launches an application, opens a document or prints a document.
|
44
44
|
#
|
45
|
-
# See:
|
45
|
+
# See: PDF2.0 s12.6.4.6
|
46
46
|
class Launch < Action
|
47
47
|
|
48
48
|
# The type used for the /Win field of a Launch action dictionary.
|
@@ -0,0 +1,86 @@
|
|
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-2023 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/type/action'
|
38
|
+
|
39
|
+
module HexaPDF
|
40
|
+
module Type
|
41
|
+
module Actions
|
42
|
+
|
43
|
+
# A Set-OCG-state action changes the state of one or more optional content groups.
|
44
|
+
#
|
45
|
+
# See: PDF2.0 s12.6.4.13, HexaPDF::Type::OptionalContentGroup
|
46
|
+
class SetOCGState < Action
|
47
|
+
|
48
|
+
define_field :S, type: Symbol, required: true, default: :SetOCGState
|
49
|
+
define_field :State, type: PDFArray, required: true, default: []
|
50
|
+
define_field :PreserveRB, type: Boolean, default: true
|
51
|
+
|
52
|
+
STATE_TYPE_MAPPING = {on: :ON, ON: :ON, off: :OFF, OFF: :OFF, # :nodoc:
|
53
|
+
toggle: :Toggle, Toggle: :Toggle}
|
54
|
+
|
55
|
+
# Adds a state changing sequence to the /State array.
|
56
|
+
#
|
57
|
+
# The +type+ argument specifies how the state of the given optional content groups should be
|
58
|
+
# changed.
|
59
|
+
#
|
60
|
+
# +type+:: The type of sequence to add, either :on/:ON (for turning the OCGs on) , :off/:OFF
|
61
|
+
# (for turning the OCGs off), or :toggle/:Toggle (for toggling the state of the
|
62
|
+
# OCGs).
|
63
|
+
#
|
64
|
+
# +ocgs+:: A single optional content group or an array of optional content groups to which
|
65
|
+
# the state change defined with +type+ should be applied. The OCGs can be specified
|
66
|
+
# via their dictionary or by name which uses the first found OCG with that name.
|
67
|
+
def add_state_change(type, ocgs)
|
68
|
+
type = STATE_TYPE_MAPPING.fetch(type) do
|
69
|
+
raise ArgumentError, "Invalid type #{type} specified, should be one of :on, :off or :toggle"
|
70
|
+
end
|
71
|
+
state = self[:State]
|
72
|
+
state << type
|
73
|
+
Array(ocgs).each do |ocg|
|
74
|
+
if (ocg_name = ocg).kind_of?(String)
|
75
|
+
ocg = document.optional_content.ocg(ocg_name, create: false)
|
76
|
+
raise HexaPDF::Error, "Invalid OCG named '#{ocg_name}' specified" unless ocg
|
77
|
+
end
|
78
|
+
state << ocg
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/hexapdf/type/actions.rb
CHANGED
@@ -41,13 +41,14 @@ module HexaPDF
|
|
41
41
|
|
42
42
|
# Namespace module for all PDF action dictionary types.
|
43
43
|
#
|
44
|
-
# See:
|
44
|
+
# See: PDF2.0 s12.6.4, Action
|
45
45
|
module Actions
|
46
46
|
|
47
47
|
autoload(:GoTo, 'hexapdf/type/actions/go_to')
|
48
48
|
autoload(:GoToR, 'hexapdf/type/actions/go_to_r')
|
49
49
|
autoload(:Launch, 'hexapdf/type/actions/launch')
|
50
50
|
autoload(:URI, 'hexapdf/type/actions/uri')
|
51
|
+
autoload(:SetOCGState, 'hexapdf/type/actions/set_ocg_state')
|
51
52
|
|
52
53
|
end
|
53
54
|
|
@@ -43,7 +43,7 @@ module HexaPDF
|
|
43
43
|
# Annotations are used to associate objects like notes, sounds or movies with a location on a
|
44
44
|
# PDF page or allow the user to interact with a PDF document using a keyboard or mouse.
|
45
45
|
#
|
46
|
-
# See:
|
46
|
+
# See: PDF2.0 s12.5
|
47
47
|
class Annotation < Dictionary
|
48
48
|
|
49
49
|
# The appearance dictionary references appearance streams for various use cases.
|
@@ -52,7 +52,7 @@ module HexaPDF
|
|
52
52
|
# latter is used when the appearance depends on the state of the annotation, e.g. a check box
|
53
53
|
# widget that can be checked or unchecked.
|
54
54
|
#
|
55
|
-
# See:
|
55
|
+
# See: PDF2.0 s12.5.5
|
56
56
|
class AppearanceDictionary < Dictionary
|
57
57
|
|
58
58
|
define_type :XXAppearanceDictionary
|
@@ -101,7 +101,7 @@ module HexaPDF
|
|
101
101
|
|
102
102
|
# Border style dictionary used by various annotation types.
|
103
103
|
#
|
104
|
-
# See:
|
104
|
+
# See: PDF2.0 s12.5.4
|
105
105
|
class Border < Dictionary
|
106
106
|
|
107
107
|
define_type :Border
|
@@ -43,7 +43,7 @@ module HexaPDF
|
|
43
43
|
# Link annotations represent a link to a destination elsewhere in the PDF document or an
|
44
44
|
# action to be performed.
|
45
45
|
#
|
46
|
-
# See:
|
46
|
+
# See: PDF2.0 s12.5.6.5, HexaPDF::Type::Annotation
|
47
47
|
class Link < Annotation
|
48
48
|
|
49
49
|
define_field :Subtype, type: Symbol, required: true, default: :Link
|
@@ -43,7 +43,7 @@ module HexaPDF
|
|
43
43
|
# Markup annotations are used to "mark up" a PDF document, most of the available PDF
|
44
44
|
# annotations are actually markup annotations.
|
45
45
|
#
|
46
|
-
# See:
|
46
|
+
# See: PDF2.0 s12.5.6.2, HexaPDF::Type::Annotation
|
47
47
|
class MarkupAnnotation < Annotation
|
48
48
|
|
49
49
|
define_field :T, type: String, version: '1.1'
|
@@ -43,7 +43,7 @@ module HexaPDF
|
|
43
43
|
# Text annotations are "sticky notes" attached to a point in a PDF document. They act as if
|
44
44
|
# the NoZoom and NoRotate flags were always set.
|
45
45
|
#
|
46
|
-
# See:
|
46
|
+
# See: PDF2.0 s12.5.6.4, HexaPDF::Type::MarkupAnnotation
|
47
47
|
class Text < MarkupAnnotation
|
48
48
|
|
49
49
|
define_field :Subtype, type: Symbol, required: true, default: :Text
|
@@ -55,8 +55,7 @@ module HexaPDF
|
|
55
55
|
|
56
56
|
private
|
57
57
|
|
58
|
-
# :nodoc:
|
59
|
-
STATE_TO_STATE_MODEL = {
|
58
|
+
STATE_TO_STATE_MODEL = { # :nodoc:
|
60
59
|
"Marked" => "Marked", "Unmarked" => "Marked",
|
61
60
|
"Accepted" => "Review", "Rejected" => "Review", "Cancelled" => "Review",
|
62
61
|
"Completed" => "Review", "None" => "Review"
|
@@ -45,7 +45,7 @@ module HexaPDF
|
|
45
45
|
# Widget annotations are used by interactive forms to represent the appearance of fields and
|
46
46
|
# to manage user interactions.
|
47
47
|
#
|
48
|
-
# See:
|
48
|
+
# See: PDF2.0 s12.5.6.19, HexaPDF::Type::Annotation
|
49
49
|
class Widget < Annotation
|
50
50
|
|
51
51
|
# The dictionary used by the /MK key of the widget annotation.
|
@@ -264,7 +264,7 @@ module HexaPDF
|
|
264
264
|
# the /DA key on the widget (although /DA is not defined for widget, this is how Acrobat
|
265
265
|
# does it).
|
266
266
|
#
|
267
|
-
# See:
|
267
|
+
# See: PDF2.0 s12.5.6.19 and s12.7.4.3
|
268
268
|
def marker_style(style: nil, size: nil, color: nil)
|
269
269
|
field = form_field
|
270
270
|
if style || size || color
|
@@ -41,7 +41,7 @@ module HexaPDF
|
|
41
41
|
|
42
42
|
# Namespace module for all PDF annotation dictionary types.
|
43
43
|
#
|
44
|
-
# See:
|
44
|
+
# See: PDF2.0 s12.5.6, Annotation
|
45
45
|
module Annotations
|
46
46
|
|
47
47
|
autoload(:MarkupAnnotation, 'hexapdf/type/annotations/markup_annotation')
|
data/lib/hexapdf/type/catalog.rb
CHANGED
@@ -46,7 +46,7 @@ module HexaPDF
|
|
46
46
|
#
|
47
47
|
# The catalog dictionary is linked via the /Root entry from the Trailer.
|
48
48
|
#
|
49
|
-
# See:
|
49
|
+
# See: PDF2.0 s7.7.2, Trailer
|
50
50
|
class Catalog < Dictionary
|
51
51
|
|
52
52
|
define_type :Catalog
|
@@ -78,7 +78,7 @@ module HexaPDF
|
|
78
78
|
define_field :SpiderInfo, type: Dictionary, version: '1.3'
|
79
79
|
define_field :OutputIntents, type: PDFArray, version: '1.4'
|
80
80
|
define_field :PieceInfo, type: Dictionary, version: '1.4'
|
81
|
-
define_field :OCProperties, type:
|
81
|
+
define_field :OCProperties, type: :XXOCProperties, version: '1.5'
|
82
82
|
define_field :Perms, type: Dictionary, version: '1.5'
|
83
83
|
define_field :Legal, type: Dictionary, version: '1.5'
|
84
84
|
define_field :Requirements, type: PDFArray, version: '1.7'
|
@@ -112,6 +112,15 @@ module HexaPDF
|
|
112
112
|
self[:Outlines] ||= document.add({}, type: :Outlines)
|
113
113
|
end
|
114
114
|
|
115
|
+
# Returns the optional content properties dictionary, creating it if needed.
|
116
|
+
#
|
117
|
+
# This is the main entry point for working with optional content, a.k.a. layers.
|
118
|
+
#
|
119
|
+
# See: OptionalContentProperties
|
120
|
+
def optional_content
|
121
|
+
self[:OCProperties] ||= document.add({OCGs: [], D: {Creator: 'HexaPDF'}}, type: :XXOCProperties)
|
122
|
+
end
|
123
|
+
|
115
124
|
# Returns the main AcroForm object.
|
116
125
|
#
|
117
126
|
# * If an AcroForm object exists, the +create+ argument is not used.
|
@@ -42,13 +42,27 @@ module HexaPDF
|
|
42
42
|
# Represents a generic CIDFont which can only be used as a descendant font of a composite PDF
|
43
43
|
# font.
|
44
44
|
#
|
45
|
-
# See:
|
45
|
+
# See: PDF2.0 s9.7.4
|
46
46
|
class CIDFont < Font
|
47
47
|
|
48
|
+
# Describes the CIDSystemInfo dictionary specifying the character collection assumed by the
|
49
|
+
# CIDFont.
|
50
|
+
#
|
51
|
+
# See: PDF2.0 s9.7.3
|
52
|
+
class CIDSystemInfo < Dictionary
|
53
|
+
|
54
|
+
define_type :XXCIDSystemInfo
|
55
|
+
|
56
|
+
define_field :Registry, type: String, required: true
|
57
|
+
define_field :Ordering, type: String, required: true
|
58
|
+
define_field :Supplement, type: Integer, required: true
|
59
|
+
|
60
|
+
end
|
61
|
+
|
48
62
|
DEFAULT_WIDTH = 1000 # :nodoc:
|
49
63
|
|
50
64
|
define_field :BaseFont, type: Symbol, required: true
|
51
|
-
define_field :CIDSystemInfo, type:
|
65
|
+
define_field :CIDSystemInfo, type: :XXCIDSystemInfo, required: true
|
52
66
|
define_field :FontDescriptor, type: :FontDescriptor, indirect: true, required: true
|
53
67
|
define_field :DW, type: Integer, default: DEFAULT_WIDTH
|
54
68
|
define_field :W, type: PDFArray
|
@@ -66,7 +80,7 @@ module HexaPDF
|
|
66
80
|
# Sets the /W and /DW keys using the given array of [CID, width] pairs and an optional default
|
67
81
|
# width.
|
68
82
|
#
|
69
|
-
# See:
|
83
|
+
# See: PDF2.0 s9.7.4.3
|
70
84
|
def set_widths(widths, default_width: DEFAULT_WIDTH)
|
71
85
|
if widths.empty?
|
72
86
|
(default_width == DEFAULT_WIDTH ? delete(:DW) : self[:DW] = default_width)
|
@@ -93,7 +107,7 @@ module HexaPDF
|
|
93
107
|
#
|
94
108
|
# Note that the hash is cached internally when accessed the first time.
|
95
109
|
#
|
96
|
-
# See:
|
110
|
+
# See: PDF2.0 s9.7.4.3
|
97
111
|
def widths
|
98
112
|
cache(:widths) do
|
99
113
|
result = {}
|
@@ -46,7 +46,7 @@ module HexaPDF
|
|
46
46
|
# Type::FileSpecification dictionary or with the document as a whole through the /EmbeddedFiles
|
47
47
|
# entry in the document catalog's /Names dictionary.
|
48
48
|
#
|
49
|
-
# See:
|
49
|
+
# See: PDF2.0 s7.11.4, FileSpecification
|
50
50
|
class EmbeddedFile < Stream
|
51
51
|
|
52
52
|
# The type used for the /Mac field of an EmbeddedFile::Parameters dictionary.
|