hexapdf 0.11.7 → 0.12.2
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 +121 -0
- data/LICENSE +1 -1
- data/examples/001-hello_world.rb +1 -1
- data/examples/002-graphics.rb +1 -1
- data/examples/003-arcs.rb +1 -1
- data/examples/004-optimizing.rb +1 -1
- data/examples/005-merging.rb +1 -1
- data/examples/006-standard_pdf_fonts.rb +1 -1
- data/examples/007-truetype.rb +1 -1
- data/examples/008-show_char_bboxes.rb +1 -1
- data/examples/009-text_layouter_alignment.rb +1 -1
- data/examples/010-text_layouter_inline_boxes.rb +1 -1
- data/examples/011-text_layouter_line_wrapping.rb +1 -1
- data/examples/012-text_layouter_styling.rb +1 -1
- data/examples/013-text_layouter_shapes.rb +1 -1
- data/examples/014-text_in_polygon.rb +1 -1
- data/examples/015-boxes.rb +1 -1
- data/examples/016-frame_automatic_box_placement.rb +1 -1
- data/examples/017-frame_text_flow.rb +1 -1
- data/examples/018-composer.rb +1 -1
- data/examples/019-acro_form.rb +51 -0
- data/lib/hexapdf.rb +1 -1
- data/lib/hexapdf/cli.rb +3 -1
- data/lib/hexapdf/cli/batch.rb +1 -1
- data/lib/hexapdf/cli/command.rb +18 -9
- data/lib/hexapdf/cli/files.rb +1 -1
- data/lib/hexapdf/cli/form.rb +240 -0
- data/lib/hexapdf/cli/image2pdf.rb +1 -1
- data/lib/hexapdf/cli/images.rb +1 -1
- data/lib/hexapdf/cli/info.rb +1 -1
- data/lib/hexapdf/cli/inspect.rb +1 -1
- data/lib/hexapdf/cli/merge.rb +1 -1
- data/lib/hexapdf/cli/modify.rb +1 -1
- data/lib/hexapdf/cli/optimize.rb +1 -1
- data/lib/hexapdf/cli/split.rb +1 -1
- data/lib/hexapdf/cli/watermark.rb +1 -1
- data/lib/hexapdf/composer.rb +2 -2
- data/lib/hexapdf/configuration.rb +66 -11
- data/lib/hexapdf/content.rb +3 -1
- data/lib/hexapdf/content/canvas.rb +5 -18
- data/lib/hexapdf/content/color_space.rb +111 -32
- data/lib/hexapdf/content/graphic_object.rb +1 -1
- data/lib/hexapdf/content/graphic_object/arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
- data/lib/hexapdf/content/graphics_state.rb +1 -1
- data/lib/hexapdf/content/operator.rb +9 -9
- data/lib/hexapdf/content/parser.rb +18 -5
- data/lib/hexapdf/content/processor.rb +1 -1
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/data_dir.rb +1 -1
- data/lib/hexapdf/dictionary.rb +1 -1
- data/lib/hexapdf/dictionary_fields.rb +1 -1
- data/lib/hexapdf/document.rb +14 -5
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +1 -1
- data/lib/hexapdf/document/images.rb +1 -1
- data/lib/hexapdf/document/pages.rb +3 -14
- data/lib/hexapdf/encryption.rb +1 -1
- data/lib/hexapdf/encryption/aes.rb +1 -1
- data/lib/hexapdf/encryption/arc4.rb +1 -1
- data/lib/hexapdf/encryption/fast_aes.rb +1 -1
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/identity.rb +1 -1
- data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
- data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +7 -1
- data/lib/hexapdf/encryption/standard_security_handler.rb +1 -1
- data/lib/hexapdf/error.rb +1 -1
- data/lib/hexapdf/filter.rb +3 -3
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/encryption.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/{jpx_decode.rb → pass_through.rb} +5 -5
- data/lib/hexapdf/filter/predictor.rb +1 -1
- data/lib/hexapdf/filter/run_length_decode.rb +1 -1
- data/lib/hexapdf/font/cmap.rb +1 -1
- data/lib/hexapdf/font/cmap/parser.rb +1 -1
- data/lib/hexapdf/font/cmap/writer.rb +1 -1
- data/lib/hexapdf/font/encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/base.rb +9 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +7 -1
- data/lib/hexapdf/font/encoding/glyph_list.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
- 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 +1 -1
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
- data/lib/hexapdf/font/invalid_glyph.rb +1 -1
- data/lib/hexapdf/font/true_type.rb +1 -1
- data/lib/hexapdf/font/true_type/builder.rb +1 -1
- data/lib/hexapdf/font/true_type/font.rb +1 -1
- data/lib/hexapdf/font/true_type/optimizer.rb +1 -1
- data/lib/hexapdf/font/true_type/subsetter.rb +1 -1
- data/lib/hexapdf/font/true_type/table.rb +1 -1
- data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
- data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
- data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
- data/lib/hexapdf/font/true_type/table/glyf.rb +1 -1
- data/lib/hexapdf/font/true_type/table/head.rb +1 -1
- data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
- data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
- data/lib/hexapdf/font/true_type/table/kern.rb +1 -1
- data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
- data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
- data/lib/hexapdf/font/true_type/table/name.rb +1 -1
- data/lib/hexapdf/font/true_type/table/os2.rb +1 -1
- data/lib/hexapdf/font/true_type/table/post.rb +1 -1
- data/lib/hexapdf/font/true_type_wrapper.rb +54 -51
- data/lib/hexapdf/font/type1.rb +1 -1
- data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
- data/lib/hexapdf/font/type1_wrapper.rb +68 -52
- data/lib/hexapdf/font_loader.rb +1 -1
- data/lib/hexapdf/font_loader/from_configuration.rb +1 -1
- data/lib/hexapdf/font_loader/from_file.rb +1 -1
- data/lib/hexapdf/font_loader/standard14.rb +1 -1
- data/lib/hexapdf/image_loader.rb +1 -1
- data/lib/hexapdf/image_loader/jpeg.rb +1 -1
- data/lib/hexapdf/image_loader/pdf.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +1 -1
- data/lib/hexapdf/importer.rb +2 -4
- data/lib/hexapdf/layout.rb +1 -1
- data/lib/hexapdf/layout/box.rb +1 -1
- data/lib/hexapdf/layout/frame.rb +1 -1
- data/lib/hexapdf/layout/image_box.rb +1 -1
- data/lib/hexapdf/layout/inline_box.rb +1 -1
- data/lib/hexapdf/layout/line.rb +1 -1
- data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
- data/lib/hexapdf/layout/style.rb +1 -1
- data/lib/hexapdf/layout/text_box.rb +1 -1
- data/lib/hexapdf/layout/text_fragment.rb +1 -1
- data/lib/hexapdf/layout/text_layouter.rb +1 -1
- data/lib/hexapdf/layout/text_shaper.rb +1 -1
- data/lib/hexapdf/layout/width_from_polygon.rb +1 -1
- data/lib/hexapdf/name_tree_node.rb +1 -1
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/object.rb +2 -2
- data/lib/hexapdf/parser.rb +4 -3
- data/lib/hexapdf/pdf_array.rb +1 -1
- data/lib/hexapdf/rectangle.rb +31 -1
- data/lib/hexapdf/reference.rb +1 -1
- data/lib/hexapdf/revision.rb +2 -1
- data/lib/hexapdf/revisions.rb +1 -1
- data/lib/hexapdf/serializer.rb +2 -2
- data/lib/hexapdf/stream.rb +1 -1
- data/lib/hexapdf/task.rb +1 -1
- data/lib/hexapdf/task/dereference.rb +1 -1
- data/lib/hexapdf/task/optimize.rb +1 -1
- data/lib/hexapdf/tokenizer.rb +1 -1
- data/lib/hexapdf/type.rb +1 -1
- data/lib/hexapdf/type/acro_form.rb +7 -1
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +401 -0
- data/lib/hexapdf/type/acro_form/button_field.rb +300 -0
- data/lib/hexapdf/type/acro_form/choice_field.rb +220 -0
- data/lib/hexapdf/type/acro_form/field.rb +220 -17
- data/lib/hexapdf/type/acro_form/form.rb +157 -7
- data/lib/hexapdf/type/acro_form/text_field.rb +186 -0
- data/lib/hexapdf/type/acro_form/variable_text_field.rb +122 -0
- data/lib/hexapdf/type/action.rb +1 -1
- data/lib/hexapdf/type/actions.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/uri.rb +1 -1
- data/lib/hexapdf/type/annotation.rb +73 -3
- data/lib/hexapdf/type/annotations.rb +1 -1
- data/lib/hexapdf/type/annotations/link.rb +2 -2
- data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
- data/lib/hexapdf/type/annotations/text.rb +1 -1
- data/lib/hexapdf/type/annotations/widget.rb +239 -2
- data/lib/hexapdf/type/catalog.rb +21 -1
- data/lib/hexapdf/type/cid_font.rb +1 -1
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +1 -1
- data/lib/hexapdf/type/font.rb +18 -1
- data/lib/hexapdf/type/font_descriptor.rb +2 -2
- data/lib/hexapdf/type/font_simple.rb +1 -1
- data/lib/hexapdf/type/font_true_type.rb +1 -1
- data/lib/hexapdf/type/font_type0.rb +1 -1
- data/lib/hexapdf/type/font_type1.rb +16 -1
- data/lib/hexapdf/type/font_type3.rb +1 -1
- data/lib/hexapdf/type/form.rb +10 -1
- 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 +3 -1
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/names.rb +1 -1
- data/lib/hexapdf/type/object_stream.rb +1 -1
- data/lib/hexapdf/type/page.rb +20 -5
- data/lib/hexapdf/type/page_tree_node.rb +8 -11
- data/lib/hexapdf/type/resources.rb +16 -3
- data/lib/hexapdf/type/trailer.rb +2 -3
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +1 -1
- data/lib/hexapdf/utils/bit_field.rb +38 -24
- data/lib/hexapdf/utils/bit_stream.rb +1 -1
- data/lib/hexapdf/utils/graphics_helpers.rb +1 -1
- data/lib/hexapdf/utils/lru_cache.rb +1 -1
- data/lib/hexapdf/utils/math_helpers.rb +1 -1
- data/lib/hexapdf/utils/object_hash.rb +1 -1
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
- data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
- data/lib/hexapdf/version.rb +2 -2
- data/lib/hexapdf/writer.rb +1 -1
- data/lib/hexapdf/xref_section.rb +1 -1
- data/test/hexapdf/content/common.rb +2 -2
- data/test/hexapdf/content/test_color_space.rb +71 -8
- data/test/hexapdf/content/test_operator.rb +22 -22
- data/test/hexapdf/content/test_parser.rb +14 -0
- data/test/hexapdf/document/test_fonts.rb +1 -1
- data/test/hexapdf/document/test_pages.rb +6 -6
- data/test/hexapdf/encryption/test_security_handler.rb +4 -0
- data/test/hexapdf/font/encoding/test_base.rb +10 -0
- data/test/hexapdf/font/encoding/test_difference_encoding.rb +8 -0
- data/test/hexapdf/font/test_true_type_wrapper.rb +10 -7
- data/test/hexapdf/font/test_type1_wrapper.rb +33 -8
- data/test/hexapdf/layout/test_style.rb +1 -1
- data/test/hexapdf/test_document.rb +12 -0
- data/test/hexapdf/test_parser.rb +10 -0
- data/test/hexapdf/test_rectangle.rb +14 -0
- data/test/hexapdf/test_revision.rb +3 -0
- data/test/hexapdf/test_serializer.rb +3 -3
- data/test/hexapdf/test_writer.rb +2 -2
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +515 -0
- data/test/hexapdf/type/acro_form/test_button_field.rb +276 -0
- data/test/hexapdf/type/acro_form/test_choice_field.rb +137 -0
- data/test/hexapdf/type/acro_form/test_field.rb +124 -6
- data/test/hexapdf/type/acro_form/test_form.rb +189 -22
- data/test/hexapdf/type/acro_form/test_text_field.rb +119 -0
- data/test/hexapdf/type/acro_form/test_variable_text_field.rb +77 -0
- data/test/hexapdf/type/annotations/test_text.rb +1 -1
- data/test/hexapdf/type/annotations/test_widget.rb +199 -0
- data/test/hexapdf/type/test_annotation.rb +45 -0
- data/test/hexapdf/type/test_catalog.rb +18 -0
- data/test/hexapdf/type/test_font.rb +5 -0
- data/test/hexapdf/type/test_font_type1.rb +8 -0
- data/test/hexapdf/type/test_form.rb +18 -0
- data/test/hexapdf/type/test_image.rb +7 -0
- data/test/hexapdf/type/test_page.rb +37 -6
- data/test/hexapdf/type/test_page_tree_node.rb +20 -12
- data/test/hexapdf/type/test_resources.rb +20 -0
- data/test/hexapdf/type/test_trailer.rb +4 -0
- data/test/hexapdf/utils/test_bit_field.rb +13 -1
- data/test/test_helper.rb +1 -1
- metadata +38 -18
- data/lib/hexapdf/filter/dct_decode.rb +0 -60
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/object.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -132,7 +132,7 @@ module HexaPDF
|
|
|
132
132
|
def self.deep_copy(object)
|
|
133
133
|
case object
|
|
134
134
|
when Hash
|
|
135
|
-
object.
|
|
135
|
+
object.transform_values {|value| deep_copy(value) }
|
|
136
136
|
when Array
|
|
137
137
|
object.map {|o| deep_copy(o) }
|
|
138
138
|
when HexaPDF::Object
|
data/lib/hexapdf/parser.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -281,7 +281,8 @@ module HexaPDF
|
|
|
281
281
|
@io.seek(0, IO::SEEK_END)
|
|
282
282
|
step_size = 1024
|
|
283
283
|
pos = @io.pos
|
|
284
|
-
eof_not_found =
|
|
284
|
+
eof_not_found = pos == 0
|
|
285
|
+
startxref_missing = false
|
|
285
286
|
|
|
286
287
|
while pos != 0
|
|
287
288
|
@io.pos = [pos - step_size, 0].max
|
|
@@ -333,7 +334,7 @@ module HexaPDF
|
|
|
333
334
|
# See: PDF1.7 s7.5.2, ADB1.7 sH.3-3.4.1
|
|
334
335
|
def retrieve_pdf_header_offset_and_version
|
|
335
336
|
@io.seek(0)
|
|
336
|
-
@header_offset = @io.read(1024).index(/%PDF-(\d\.\d)/) || 0
|
|
337
|
+
@header_offset = (@io.read(1024) || '').index(/%PDF-(\d\.\d)/) || 0
|
|
337
338
|
@header_version = $1
|
|
338
339
|
end
|
|
339
340
|
|
data/lib/hexapdf/pdf_array.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/rectangle.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -59,31 +59,61 @@ module HexaPDF
|
|
|
59
59
|
self[0]
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
# Sets the x-coordinate of the bottom-left corner to the given value.
|
|
63
|
+
def left=(x)
|
|
64
|
+
value[0] = x
|
|
65
|
+
end
|
|
66
|
+
|
|
62
67
|
# Returns the x-coordinate of the top-right corner.
|
|
63
68
|
def right
|
|
64
69
|
self[2]
|
|
65
70
|
end
|
|
66
71
|
|
|
72
|
+
# Sets the x-coordinate of the top-right corner to the given value.
|
|
73
|
+
def right=(x)
|
|
74
|
+
value[2] = x
|
|
75
|
+
end
|
|
76
|
+
|
|
67
77
|
# Returns the y-coordinate of the bottom-left corner.
|
|
68
78
|
def bottom
|
|
69
79
|
self[1]
|
|
70
80
|
end
|
|
71
81
|
|
|
82
|
+
# Sets the y-coordinate of the bottom-left corner to the given value.
|
|
83
|
+
def bottom=(y)
|
|
84
|
+
value[1] = y
|
|
85
|
+
end
|
|
86
|
+
|
|
72
87
|
# Returns the y-coordinate of the top-right corner.
|
|
73
88
|
def top
|
|
74
89
|
self[3]
|
|
75
90
|
end
|
|
76
91
|
|
|
92
|
+
# Sets the y-coordinate of the top-right corner to the given value.
|
|
93
|
+
def top=(y)
|
|
94
|
+
value[3] = y
|
|
95
|
+
end
|
|
96
|
+
|
|
77
97
|
# Returns the width of the rectangle.
|
|
78
98
|
def width
|
|
79
99
|
self[2] - self[0]
|
|
80
100
|
end
|
|
81
101
|
|
|
102
|
+
# Sets the width of the rectangle to the given value.
|
|
103
|
+
def width=(val)
|
|
104
|
+
self[2] = self[0] + val
|
|
105
|
+
end
|
|
106
|
+
|
|
82
107
|
# Returns the height of the rectangle.
|
|
83
108
|
def height
|
|
84
109
|
self[3] - self[1]
|
|
85
110
|
end
|
|
86
111
|
|
|
112
|
+
# Sets the height of the rectangle to the given value.
|
|
113
|
+
def height=(val)
|
|
114
|
+
self[3] = self[1] + val
|
|
115
|
+
end
|
|
116
|
+
|
|
87
117
|
# Compares this rectangle to +other+ like in Object#== but also allows comparison to simple
|
|
88
118
|
# arrays if the rectangle is a direct object.
|
|
89
119
|
def ==(other)
|
data/lib/hexapdf/reference.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/revision.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -172,6 +172,7 @@ module HexaPDF
|
|
|
172
172
|
|
|
173
173
|
obj = object(ref_or_oid)
|
|
174
174
|
obj.data.value = nil
|
|
175
|
+
obj.document = nil
|
|
175
176
|
if mark_as_free
|
|
176
177
|
add_without_check(HexaPDF::Object.new(nil, oid: obj.oid, gen: obj.gen))
|
|
177
178
|
else
|
data/lib/hexapdf/revisions.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/serializer.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -187,7 +187,7 @@ module HexaPDF
|
|
|
187
187
|
begin
|
|
188
188
|
str = obj.to_s.dup.force_encoding(Encoding::BINARY)
|
|
189
189
|
str.gsub!(NAME_REGEXP, NAME_SUBSTS)
|
|
190
|
-
"/#{str}"
|
|
190
|
+
str.empty? ? "/ " : "/#{str}"
|
|
191
191
|
end
|
|
192
192
|
end
|
|
193
193
|
|
data/lib/hexapdf/stream.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/task.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/tokenizer.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/type.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2020 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -44,6 +44,12 @@ module HexaPDF
|
|
|
44
44
|
|
|
45
45
|
autoload(:Form, 'hexapdf/type/acro_form/form')
|
|
46
46
|
autoload(:Field, 'hexapdf/type/acro_form/field')
|
|
47
|
+
autoload(:VariableTextField, 'hexapdf/type/acro_form/variable_text_field')
|
|
48
|
+
autoload(:TextField, 'hexapdf/type/acro_form/text_field')
|
|
49
|
+
autoload(:ButtonField, 'hexapdf/type/acro_form/button_field')
|
|
50
|
+
autoload(:ChoiceField, 'hexapdf/type/acro_form/choice_field')
|
|
51
|
+
|
|
52
|
+
autoload(:AppearanceGenerator, 'hexapdf/type/acro_form/appearance_generator')
|
|
47
53
|
|
|
48
54
|
end
|
|
49
55
|
|
|
@@ -0,0 +1,401 @@
|
|
|
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
|
+
require 'hexapdf/layout/style'
|
|
39
|
+
require 'hexapdf/layout/text_fragment'
|
|
40
|
+
|
|
41
|
+
module HexaPDF
|
|
42
|
+
module Type
|
|
43
|
+
module AcroForm
|
|
44
|
+
|
|
45
|
+
# The AppearanceGenerator class provides methods for generating and updating the appearance
|
|
46
|
+
# streams of form fields.
|
|
47
|
+
#
|
|
48
|
+
# The only method needed is #create_appearances since this method determines to what field the
|
|
49
|
+
# widget belongs and therefore which appearance should be generated.
|
|
50
|
+
#
|
|
51
|
+
# The visual appearance of a field is constructed using information from the field itself as
|
|
52
|
+
# well as information from the widget. See the documentation for the individual methods which
|
|
53
|
+
# information is used in which way.
|
|
54
|
+
#
|
|
55
|
+
# By default, any existing appearances are overwritten and the +:print+ flag is set on the
|
|
56
|
+
# widget so that the field appearance will appear on print-outs.
|
|
57
|
+
#
|
|
58
|
+
# The visual appearances are chosen to be similar to those used by Adobe Acrobat and others.
|
|
59
|
+
# By subclassing and overriding the necessary methods it is possible to define custom
|
|
60
|
+
# appearances.
|
|
61
|
+
#
|
|
62
|
+
# See: PDF1.7 s12.5.5, s12.7
|
|
63
|
+
class AppearanceGenerator
|
|
64
|
+
|
|
65
|
+
# Creates a new instance for the given +widget+.
|
|
66
|
+
def initialize(widget)
|
|
67
|
+
@widget = widget
|
|
68
|
+
@field = widget.form_field
|
|
69
|
+
@document = widget.document
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Creates the appropriate appearances for the widget.
|
|
73
|
+
def create_appearances
|
|
74
|
+
case @field.field_type
|
|
75
|
+
when :Btn
|
|
76
|
+
if @field.check_box?
|
|
77
|
+
create_check_box_appearances
|
|
78
|
+
elsif @field.radio_button?
|
|
79
|
+
create_radio_button_appearances
|
|
80
|
+
else
|
|
81
|
+
raise HexaPDF::Error, "Unsupported button field type"
|
|
82
|
+
end
|
|
83
|
+
when :Tx
|
|
84
|
+
create_text_appearances
|
|
85
|
+
when :Ch
|
|
86
|
+
if @field.combo_box?
|
|
87
|
+
create_text_appearances
|
|
88
|
+
else
|
|
89
|
+
raise HexaPDF::Error, "List box not supported yet"
|
|
90
|
+
end
|
|
91
|
+
else
|
|
92
|
+
raise HexaPDF::Error, "Unsupported field type #{@field.field_type}"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Creates the appropriate appearances for check boxes.
|
|
97
|
+
#
|
|
98
|
+
# For unchecked boxes an empty rectangle is drawn. When checked, a symbol from the
|
|
99
|
+
# ZapfDingbats font is placed inside the rectangle. How this is exactly done depends on the
|
|
100
|
+
# following values:
|
|
101
|
+
#
|
|
102
|
+
# * The widget's rectangle /Rect must be defined. If the height and/or width of the
|
|
103
|
+
# rectangle are zero, they are based on the configuration option
|
|
104
|
+
# +acro_form.default_font_size+ and widget's border width. In such a case the rectangle is
|
|
105
|
+
# appropriately updated.
|
|
106
|
+
#
|
|
107
|
+
# * The line width, style and color of the rectangle are taken from the widget's border
|
|
108
|
+
# style. See HexaPDF::Type::Annotations::Widget#border_style.
|
|
109
|
+
#
|
|
110
|
+
# * The background color is determined by the widget's background color. See
|
|
111
|
+
# HexaPDF::Type::Annotations::Widget#background_color.
|
|
112
|
+
#
|
|
113
|
+
# * The symbol (marker) as well as its size and color are determined by the marker style of
|
|
114
|
+
# the widget. See HexaPDF::Type::Annotations::Widget#marker_style for details.
|
|
115
|
+
#
|
|
116
|
+
# Examples:
|
|
117
|
+
#
|
|
118
|
+
# widget.border_style(color: 0)
|
|
119
|
+
# widget.background_color(1)
|
|
120
|
+
# widget.marker_style(style: :check, size: 0, color: 0)
|
|
121
|
+
# # => default appearance
|
|
122
|
+
#
|
|
123
|
+
# widget.border_style(color: :transparent, width: 2)
|
|
124
|
+
# widget.background_color(0.7)
|
|
125
|
+
# widget.marker_style(style: :cross)
|
|
126
|
+
# # => no visible rectangle, gray background, cross mark when checked
|
|
127
|
+
def create_check_box_appearances
|
|
128
|
+
unless @widget.appearance&.normal_appearance&.value&.size == 2
|
|
129
|
+
raise HexaPDF::Error, "Widget of check box doesn't define name for on state"
|
|
130
|
+
end
|
|
131
|
+
border_style = @widget.border_style
|
|
132
|
+
border_width = border_style.width
|
|
133
|
+
|
|
134
|
+
rect = update_widget(@field[:V], border_width)
|
|
135
|
+
|
|
136
|
+
off_form = @widget.appearance.normal_appearance[:Off] =
|
|
137
|
+
@document.add({Type: :XObject, Subtype: :Form, BBox: [0, 0, rect.width, rect.height]})
|
|
138
|
+
apply_background_and_border(border_style, off_form.canvas)
|
|
139
|
+
|
|
140
|
+
on_form = @widget.appearance.normal_appearance[@field.check_box_on_name] =
|
|
141
|
+
@document.add({Type: :XObject, Subtype: :Form, BBox: [0, 0, rect.width, rect.height]})
|
|
142
|
+
canvas = on_form.canvas
|
|
143
|
+
apply_background_and_border(border_style, canvas)
|
|
144
|
+
canvas.save_graphics_state do
|
|
145
|
+
draw_marker(canvas, rect, border_width, @widget.marker_style)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Creates the appropriate appearances for radio buttons.
|
|
150
|
+
#
|
|
151
|
+
# For unselected radio buttons an empty circle (if the marker is :circle) or rectangle is
|
|
152
|
+
# drawn inside the widget annotation's rectangle. When selected, a symbol from the
|
|
153
|
+
# ZapfDingbats font is placed inside. How this is exactly done depends on the following
|
|
154
|
+
# values:
|
|
155
|
+
#
|
|
156
|
+
# * The widget's rectangle /Rect must be defined. If the height and/or width of the
|
|
157
|
+
# rectangle are zero, they are based on the configuration option
|
|
158
|
+
# +acro_form.default_font_size+ and the widget's border width. In such a case the
|
|
159
|
+
# rectangle is appropriately updated.
|
|
160
|
+
#
|
|
161
|
+
# * The line width, style and color of the circle/rectangle are taken from the widget's
|
|
162
|
+
# border style. See HexaPDF::Type::Annotations::Widget#border_style.
|
|
163
|
+
#
|
|
164
|
+
# * The background color is determined by the widget's background color. See
|
|
165
|
+
# HexaPDF::Type::Annotations::Widget#background_color.
|
|
166
|
+
#
|
|
167
|
+
# * The symbol (marker) as well as its size and color are determined by the marker style of
|
|
168
|
+
# the widget. See HexaPDF::Type::Annotations::Widget#marker_style for details.
|
|
169
|
+
#
|
|
170
|
+
# Examples:
|
|
171
|
+
#
|
|
172
|
+
# widget.border_style(color: 0)
|
|
173
|
+
# widget.background_color(1)
|
|
174
|
+
# widget.marker_style(style: :circle, size: 0, color: 0)
|
|
175
|
+
# # => default appearance
|
|
176
|
+
def create_radio_button_appearances
|
|
177
|
+
unless @widget.appearance&.normal_appearance&.value&.size == 2
|
|
178
|
+
raise HexaPDF::Error, "Widget of radio button doesn't define unique name for on state"
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
on_name = (@widget.appearance.normal_appearance.value.keys - [:Off]).first
|
|
182
|
+
border_style = @widget.border_style
|
|
183
|
+
marker_style = @widget.marker_style
|
|
184
|
+
|
|
185
|
+
rect = update_widget(@field[:V] == on_name ? on_name : :Off, border_style.width)
|
|
186
|
+
|
|
187
|
+
off_form = @widget.appearance.normal_appearance[:Off] =
|
|
188
|
+
@document.add({Type: :XObject, Subtype: :Form, BBox: [0, 0, rect.width, rect.height]})
|
|
189
|
+
apply_background_and_border(border_style, off_form.canvas,
|
|
190
|
+
circular: marker_style.style == :circle)
|
|
191
|
+
|
|
192
|
+
on_form = @widget.appearance.normal_appearance[on_name] =
|
|
193
|
+
@document.add({Type: :XObject, Subtype: :Form, BBox: [0, 0, rect.width, rect.height]})
|
|
194
|
+
canvas = on_form.canvas
|
|
195
|
+
apply_background_and_border(border_style, canvas,
|
|
196
|
+
circular: marker_style.style == :circle)
|
|
197
|
+
canvas.save_graphics_state do
|
|
198
|
+
draw_marker(canvas, rect, border_style.width, @widget.marker_style)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Creates the appropriate appearances for text fields.
|
|
203
|
+
#
|
|
204
|
+
# The following describes how the appearance is built:
|
|
205
|
+
#
|
|
206
|
+
# * The font, font size and font color are taken from the associated field's default
|
|
207
|
+
# appearance string. See VariableTextField.
|
|
208
|
+
#
|
|
209
|
+
# * The widget's rectangle /Rect must be defined. If the height is zero, it is auto-sized
|
|
210
|
+
# based on the font size. If additionally the font size is zero, a font size of
|
|
211
|
+
# +acro_form.default_font_size+ is used. If the width is zero, the
|
|
212
|
+
# +acro_form.text_field.default_width+ value is used. In such cases the rectangle is
|
|
213
|
+
# appropriately updated.
|
|
214
|
+
#
|
|
215
|
+
# * The line width, style and color of the rectangle are taken from the widget's border
|
|
216
|
+
# style. See HexaPDF::Type::Annotations::Widget#border_style.
|
|
217
|
+
#
|
|
218
|
+
# * The background color is determined by the widget's background color. See
|
|
219
|
+
# HexaPDF::Type::Annotations::Widget#background_color.
|
|
220
|
+
#
|
|
221
|
+
# Note: Multiline, comb and rich text fields are currently not supported!
|
|
222
|
+
def create_text_appearances
|
|
223
|
+
font_name, font_size = @field.parse_default_appearance_string
|
|
224
|
+
default_resources = @document.acro_form.default_resources
|
|
225
|
+
font = default_resources.font(font_name).font_wrapper
|
|
226
|
+
unless font
|
|
227
|
+
fallback_font_name, fallback_font_options = @document.config['acro_form.fallback_font']
|
|
228
|
+
if fallback_font_name
|
|
229
|
+
font = @document.fonts.add(fallback_font_name, **(fallback_font_options || {}))
|
|
230
|
+
else
|
|
231
|
+
raise(HexaPDF::Error, "Font #{font_name} of the AcroForm's default resources not usable")
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
style = HexaPDF::Layout::Style.new(font: font)
|
|
235
|
+
border_style = @widget.border_style
|
|
236
|
+
padding = [1, border_style.width].max
|
|
237
|
+
|
|
238
|
+
@widget[:AS] = :N
|
|
239
|
+
@widget.flag(:print)
|
|
240
|
+
rect = @widget[:Rect]
|
|
241
|
+
rect.width = @document.config['acro_form.text_field.default_width'] if rect.width == 0
|
|
242
|
+
if rect.height == 0
|
|
243
|
+
style.font_size = \
|
|
244
|
+
(font_size == 0 ? @document.config['acro_form.default_font_size'] : font_size)
|
|
245
|
+
rect.height = style.scaled_y_max - style.scaled_y_min + 2 * padding
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
form = (@widget[:AP] ||= {})[:N] = @document.add({Type: :XObject, Subtype: :Form,
|
|
249
|
+
BBox: [0, 0, rect.width, rect.height]})
|
|
250
|
+
form[:Resources] = HexaPDF::Object.deep_copy(default_resources)
|
|
251
|
+
|
|
252
|
+
canvas = form.canvas
|
|
253
|
+
apply_background_and_border(border_style, canvas)
|
|
254
|
+
style.font_size = calculate_font_size(font, font_size, rect, border_style)
|
|
255
|
+
|
|
256
|
+
canvas.marked_content_sequence(:Tx) do
|
|
257
|
+
if (value = @field.field_value)
|
|
258
|
+
canvas.save_graphics_state do
|
|
259
|
+
canvas.rectangle(padding, padding, rect.width - 2 * padding,
|
|
260
|
+
rect.height - 2 * padding).clip_path.end_path
|
|
261
|
+
fragment = HexaPDF::Layout::TextFragment.create(value, style)
|
|
262
|
+
# Adobe seems to be left/right-aligning based on twice the border width and
|
|
263
|
+
# vertically centering based on the cap height, if enough space is available
|
|
264
|
+
x = case @field.text_alignment
|
|
265
|
+
when :left then 2 * padding
|
|
266
|
+
when :right then [rect.width - 2 * padding - fragment.width, 2 * padding].max
|
|
267
|
+
when :center then [(rect.width - fragment.width) / 2.0, 2 * padding].max
|
|
268
|
+
end
|
|
269
|
+
cap_height = font.wrapped_font.cap_height * font.scaling_factor / 1000.0 *
|
|
270
|
+
style.font_size
|
|
271
|
+
y = padding + (rect.height - 2 * padding - cap_height) / 2.0
|
|
272
|
+
y = padding - style.scaled_font_descender if y < 0
|
|
273
|
+
fragment.draw(canvas, x, y)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
alias create_combo_box_appearances create_text_appearances
|
|
280
|
+
|
|
281
|
+
private
|
|
282
|
+
|
|
283
|
+
# Updates the widget and returns its (possibly modified) rectangle.
|
|
284
|
+
#
|
|
285
|
+
# The following changes are made:
|
|
286
|
+
#
|
|
287
|
+
# * Sets the appearance state to +appearance_state+.
|
|
288
|
+
# * Sets the :print flag.
|
|
289
|
+
# * Adjusts the rectangle based on the default font size and the given border width if its
|
|
290
|
+
# width and/or height are zero.
|
|
291
|
+
def update_widget(appearance_state, border_width)
|
|
292
|
+
@widget[:AS] = appearance_state
|
|
293
|
+
@widget.flag(:print)
|
|
294
|
+
|
|
295
|
+
default_font_size = @document.config['acro_form.default_font_size']
|
|
296
|
+
rect = @widget[:Rect]
|
|
297
|
+
rect.width = default_font_size + 2 * border_width if rect.width == 0
|
|
298
|
+
rect.height = default_font_size + 2 * border_width if rect.height == 0
|
|
299
|
+
rect
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Applies the background and border style of the widget annotation to the appearances.
|
|
303
|
+
#
|
|
304
|
+
# If +circular+ is +true+, then the border is drawn as inscribed circle instead of as
|
|
305
|
+
# rectangle.
|
|
306
|
+
def apply_background_and_border(border_style, canvas, circular: false)
|
|
307
|
+
rect = @widget[:Rect]
|
|
308
|
+
background_color = @widget.background_color
|
|
309
|
+
|
|
310
|
+
if (border_style.width > 0 && border_style.color) || background_color
|
|
311
|
+
canvas.save_graphics_state
|
|
312
|
+
if background_color
|
|
313
|
+
canvas.fill_color(background_color)
|
|
314
|
+
if circular
|
|
315
|
+
canvas.circle(rect.width / 2.0, rect.height / 2.0,
|
|
316
|
+
[rect.width / 2.0, rect.height / 2.0].min)
|
|
317
|
+
else
|
|
318
|
+
canvas.rectangle(0, 0, rect.width, rect.height)
|
|
319
|
+
end
|
|
320
|
+
canvas.fill
|
|
321
|
+
end
|
|
322
|
+
if border_style.color
|
|
323
|
+
offset = [0.5, border_style.width / 2.0].max
|
|
324
|
+
width, height = rect.width - 2 * offset, rect.height - 2 * offset
|
|
325
|
+
canvas.stroke_color(border_style.color).line_width(border_style.width)
|
|
326
|
+
if border_style.style == :underlined # TODO: :beveleded, :inset
|
|
327
|
+
if circular
|
|
328
|
+
canvas.arc(rect.width / 2.0, rect.height / 2.0,
|
|
329
|
+
a: [width / 2.0, height / 2.0].min,
|
|
330
|
+
start_angle: 180, end_angle: 0)
|
|
331
|
+
else
|
|
332
|
+
canvas.line(offset, offset, offset + width, offset)
|
|
333
|
+
end
|
|
334
|
+
else
|
|
335
|
+
canvas.line_dash_pattern(border_style.style) if border_style.style.kind_of?(Array)
|
|
336
|
+
if circular
|
|
337
|
+
canvas.circle(rect.width / 2.0, rect.height / 2.0, [width / 2.0, height / 2.0].min)
|
|
338
|
+
else
|
|
339
|
+
canvas.rectangle(offset, offset, width, height)
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
canvas.stroke
|
|
343
|
+
end
|
|
344
|
+
canvas.restore_graphics_state
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# Draws the marker defined by the marker style inside the widget's rectangle.
|
|
349
|
+
#
|
|
350
|
+
# This method can only used for check boxes and radio buttons!
|
|
351
|
+
def draw_marker(canvas, rect, border_width, marker_style)
|
|
352
|
+
if @field.radio_button? && marker_style.style == :circle
|
|
353
|
+
# Acrobat handles this specially
|
|
354
|
+
canvas.
|
|
355
|
+
fill_color(marker_style.color).
|
|
356
|
+
circle(rect.width / 2.0, rect.height / 2.0,
|
|
357
|
+
([rect.width / 2.0, rect.height / 2.0].min - border_width) / 2).
|
|
358
|
+
fill
|
|
359
|
+
elsif marker_style.style == :cross # Acrobat just places a cross inside
|
|
360
|
+
canvas.
|
|
361
|
+
stroke_color(marker_style.color).
|
|
362
|
+
line(border_width, border_width, rect.width - border_width,
|
|
363
|
+
rect.height - border_width).
|
|
364
|
+
line(border_width, rect.height - border_width, rect.width - border_width,
|
|
365
|
+
border_width).
|
|
366
|
+
stroke
|
|
367
|
+
else
|
|
368
|
+
font = @document.fonts.add('ZapfDingbats')
|
|
369
|
+
mark = font.decode_utf8(@widget[:MK]&.[](:CA) || '4').first
|
|
370
|
+
square_width = [rect.width, rect.height].min - 2 * border_width
|
|
371
|
+
font_size = (marker_style.size == 0 ? square_width : marker_style.size)
|
|
372
|
+
mark_width = mark.width * font.scaling_factor * font_size / 1000.0
|
|
373
|
+
mark_height = (mark.y_max - mark.y_min) * font.scaling_factor * font_size / 1000.0
|
|
374
|
+
x_offset = (rect.width - square_width) / 2.0 + (square_width - mark_width) / 2.0
|
|
375
|
+
y_offset = (rect.height - square_width) / 2.0 + (square_width - mark_height) / 2.0 -
|
|
376
|
+
(mark.y_min * font.scaling_factor * font_size / 1000.0)
|
|
377
|
+
|
|
378
|
+
canvas.font(font, size: font_size)
|
|
379
|
+
canvas.fill_color(marker_style.color)
|
|
380
|
+
canvas.move_text_cursor(offset: [x_offset, y_offset]).show_glyphs_only([mark])
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# Calculates the font size for text fields based on the font and font size of the default
|
|
385
|
+
# appearance string, the annotation rectangle and the border style.
|
|
386
|
+
def calculate_font_size(font, font_size, rect, border_style)
|
|
387
|
+
if font_size == 0
|
|
388
|
+
unit_font_size = (font.wrapped_font.bounding_box[3] - font.wrapped_font.bounding_box[1]) *
|
|
389
|
+
font.scaling_factor / 1000.0
|
|
390
|
+
# The constant factor was found empirically by checking what Adobe Reader etc. do
|
|
391
|
+
(rect.height - 2 * border_style.width) / unit_font_size * 0.83
|
|
392
|
+
else
|
|
393
|
+
font_size
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
end
|