hexapdf 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -1
- data/LICENSE +1 -1
- data/README.md +3 -0
- data/Rakefile +1 -1
- data/data/hexapdf/fonts/Inter-Bold.ttf +0 -0
- data/data/hexapdf/fonts/Inter-BoldItalic.ttf +0 -0
- data/data/hexapdf/fonts/Inter-Italic.ttf +0 -0
- data/data/hexapdf/fonts/Inter-Regular.ttf +0 -0
- data/data/hexapdf/fonts/OFL.txt +92 -0
- data/examples/005-merging.rb +2 -1
- data/examples/019-acro_form.rb +3 -1
- data/examples/030-pdfa.rb +9 -16
- data/examples/034-text_shaping.rb +37 -0
- data/lib/hexapdf/cli/batch.rb +1 -1
- data/lib/hexapdf/cli/command.rb +1 -1
- data/lib/hexapdf/cli/debug_info.rb +1 -1
- data/lib/hexapdf/cli/files.rb +1 -1
- data/lib/hexapdf/cli/fonts.rb +6 -4
- data/lib/hexapdf/cli/form.rb +1 -1
- data/lib/hexapdf/cli/image2pdf.rb +1 -1
- data/lib/hexapdf/cli/images.rb +17 -17
- data/lib/hexapdf/cli/info.rb +1 -1
- data/lib/hexapdf/cli/inspect.rb +1 -1
- data/lib/hexapdf/cli/merge.rb +14 -2
- 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/usage.rb +1 -1
- data/lib/hexapdf/cli/watermark.rb +1 -1
- data/lib/hexapdf/cli.rb +1 -1
- data/lib/hexapdf/composer.rb +1 -1
- data/lib/hexapdf/configuration.rb +15 -2
- data/lib/hexapdf/content/canvas.rb +1 -1
- data/lib/hexapdf/content/canvas_composer.rb +1 -1
- data/lib/hexapdf/content/color_space.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/graphic_object.rb +1 -1
- data/lib/hexapdf/content/graphics_state.rb +1 -1
- data/lib/hexapdf/content/operator.rb +1 -1
- data/lib/hexapdf/content/parser.rb +1 -1
- data/lib/hexapdf/content/processor.rb +1 -1
- data/lib/hexapdf/content/smart_text_extractor.rb +10 -4
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/content.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/digital_signature/cms_handler.rb +1 -1
- data/lib/hexapdf/digital_signature/handler.rb +1 -1
- data/lib/hexapdf/digital_signature/pkcs1_handler.rb +1 -1
- data/lib/hexapdf/digital_signature/signature.rb +1 -1
- data/lib/hexapdf/digital_signature/signatures.rb +1 -1
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +1 -1
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +1 -1
- data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +1 -1
- data/lib/hexapdf/digital_signature/signing.rb +1 -1
- data/lib/hexapdf/digital_signature/verification_result.rb +1 -1
- data/lib/hexapdf/digital_signature.rb +1 -1
- data/lib/hexapdf/document/annotations.rb +26 -1
- data/lib/hexapdf/document/destinations.rb +1 -1
- 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/layout.rb +1 -1
- data/lib/hexapdf/document/metadata.rb +1 -1
- data/lib/hexapdf/document/pages.rb +1 -1
- data/lib/hexapdf/document.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 +1 -1
- data/lib/hexapdf/encryption/standard_security_handler.rb +1 -1
- data/lib/hexapdf/encryption.rb +1 -1
- data/lib/hexapdf/error.rb +1 -1
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/brotli_decode.rb +1 -1
- data/lib/hexapdf/filter/crypt.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/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 +1 -1
- data/lib/hexapdf/font/cmap/parser.rb +1 -1
- data/lib/hexapdf/font/cmap/writer.rb +16 -10
- data/lib/hexapdf/font/cmap.rb +1 -1
- data/lib/hexapdf/font/encoding/base.rb +1 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -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/encoding.rb +1 -1
- data/lib/hexapdf/font/invalid_glyph.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 +4 -4
- 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/table.rb +1 -1
- data/lib/hexapdf/font/true_type.rb +1 -1
- data/lib/hexapdf/font/true_type_wrapper.rb +9 -6
- 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.rb +1 -1
- data/lib/hexapdf/font/type1_wrapper.rb +1 -1
- data/lib/hexapdf/font_loader/from_configuration.rb +1 -1
- data/lib/hexapdf/font_loader/from_file.rb +5 -1
- data/lib/hexapdf/font_loader/standard14.rb +1 -1
- data/lib/hexapdf/font_loader/variant_from_name.rb +1 -1
- data/lib/hexapdf/font_loader.rb +48 -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/image_loader.rb +1 -1
- data/lib/hexapdf/importer.rb +1 -1
- data/lib/hexapdf/layout/box.rb +1 -1
- data/lib/hexapdf/layout/box_fitter.rb +1 -1
- data/lib/hexapdf/layout/column_box.rb +1 -1
- data/lib/hexapdf/layout/container_box.rb +3 -5
- 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/list_box.rb +1 -1
- data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
- data/lib/hexapdf/layout/page_style.rb +1 -1
- data/lib/hexapdf/layout/style.rb +67 -5
- data/lib/hexapdf/layout/table_box.rb +97 -14
- data/lib/hexapdf/layout/text_box.rb +1 -1
- data/lib/hexapdf/layout/text_fragment.rb +14 -8
- data/lib/hexapdf/layout/text_layouter.rb +1 -1
- data/lib/hexapdf/layout/text_shaper.rb +163 -11
- data/lib/hexapdf/layout/width_from_polygon.rb +1 -1
- data/lib/hexapdf/layout.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 +1 -1
- data/lib/hexapdf/parser.rb +1 -1
- 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 +1 -1
- data/lib/hexapdf/serializer.rb +3 -3
- data/lib/hexapdf/stream.rb +1 -1
- data/lib/hexapdf/task/dereference.rb +1 -1
- data/lib/hexapdf/task/import_pages.rb +185 -0
- data/lib/hexapdf/task/merge_acro_form.rb +1 -1
- data/lib/hexapdf/task/optimize.rb +1 -1
- data/lib/hexapdf/task/pdfa.rb +1 -1
- data/lib/hexapdf/task.rb +2 -1
- data/lib/hexapdf/test_utils.rb +1 -1
- data/lib/hexapdf/tokenizer.rb +1 -1
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +1 -1
- 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 +1 -1
- data/lib/hexapdf/type/acro_form/form.rb +1 -1
- data/lib/hexapdf/type/acro_form/java_script_actions.rb +1 -1
- data/lib/hexapdf/type/acro_form/signature_field.rb +1 -1
- 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 +1 -1
- data/lib/hexapdf/type/actions/uri.rb +1 -1
- data/lib/hexapdf/type/actions.rb +1 -1
- data/lib/hexapdf/type/annotation.rb +1 -1
- data/lib/hexapdf/type/annotations/appearance_generator.rb +43 -1
- data/lib/hexapdf/type/annotations/border_effect.rb +1 -1
- data/lib/hexapdf/type/annotations/border_styling.rb +1 -1
- data/lib/hexapdf/type/annotations/circle.rb +1 -1
- data/lib/hexapdf/type/annotations/ink.rb +107 -0
- data/lib/hexapdf/type/annotations/interior_color.rb +1 -1
- data/lib/hexapdf/type/annotations/line.rb +1 -1
- data/lib/hexapdf/type/annotations/line_ending_styling.rb +1 -1
- data/lib/hexapdf/type/annotations/link.rb +1 -1
- data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
- data/lib/hexapdf/type/annotations/polygon.rb +1 -1
- data/lib/hexapdf/type/annotations/polygon_polyline.rb +1 -1
- data/lib/hexapdf/type/annotations/polyline.rb +1 -1
- data/lib/hexapdf/type/annotations/square.rb +1 -1
- data/lib/hexapdf/type/annotations/square_circle.rb +1 -1
- data/lib/hexapdf/type/annotations/text.rb +1 -1
- data/lib/hexapdf/type/annotations/widget.rb +1 -1
- data/lib/hexapdf/type/annotations.rb +2 -1
- data/lib/hexapdf/type/catalog.rb +1 -1
- data/lib/hexapdf/type/cid_font.rb +1 -1
- data/lib/hexapdf/type/cmap.rb +1 -1
- data/lib/hexapdf/type/document_security_store.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 +4 -4
- data/lib/hexapdf/type/font_descriptor.rb +1 -1
- 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 +1 -1
- data/lib/hexapdf/type/font_type3.rb +6 -1
- data/lib/hexapdf/type/form.rb +1 -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 +1 -1
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/mark_information.rb +1 -1
- data/lib/hexapdf/type/marked_content_reference.rb +1 -1
- data/lib/hexapdf/type/measure.rb +1 -1
- data/lib/hexapdf/type/metadata.rb +1 -1
- data/lib/hexapdf/type/names.rb +1 -1
- data/lib/hexapdf/type/namespace.rb +1 -1
- data/lib/hexapdf/type/object_reference.rb +1 -1
- data/lib/hexapdf/type/object_stream.rb +1 -1
- data/lib/hexapdf/type/optional_content_configuration.rb +1 -1
- data/lib/hexapdf/type/optional_content_group.rb +1 -1
- data/lib/hexapdf/type/optional_content_membership.rb +1 -1
- data/lib/hexapdf/type/optional_content_properties.rb +1 -1
- data/lib/hexapdf/type/outline.rb +1 -1
- data/lib/hexapdf/type/outline_item.rb +1 -1
- data/lib/hexapdf/type/output_intent.rb +1 -1
- data/lib/hexapdf/type/page.rb +1 -1
- data/lib/hexapdf/type/page_label.rb +1 -1
- data/lib/hexapdf/type/page_tree_node.rb +1 -1
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/struct_elem.rb +1 -1
- data/lib/hexapdf/type/struct_tree_root.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +1 -1
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +1 -1
- data/lib/hexapdf/type.rb +1 -1
- data/lib/hexapdf/utils/bit_field.rb +1 -1
- 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/utils.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/lib/hexapdf.rb +1 -1
- data/test/hexapdf/digital_signature/common.rb +5 -5
- data/test/hexapdf/digital_signature/test_cms_handler.rb +1 -1
- data/test/hexapdf/document/test_annotations.rb +10 -0
- data/test/hexapdf/document/test_layout.rb +6 -3
- data/test/hexapdf/filter/test_brotli_decode.rb +1 -1
- data/test/hexapdf/font/cmap/test_writer.rb +8 -6
- data/test/hexapdf/font/test_true_type_wrapper.rb +6 -2
- data/test/hexapdf/font/true_type/test_subsetter.rb +7 -6
- data/test/hexapdf/font_loader/test_from_file.rb +7 -0
- data/test/hexapdf/layout/test_container_box.rb +3 -1
- data/test/hexapdf/layout/test_style.rb +4 -0
- data/test/hexapdf/layout/test_table_box.rb +117 -1
- data/test/hexapdf/layout/test_text_fragment.rb +18 -8
- data/test/hexapdf/layout/test_text_shaper.rb +55 -5
- data/test/hexapdf/task/test_import_pages.rb +126 -0
- data/test/hexapdf/test_serializer.rb +1 -1
- data/test/hexapdf/type/annotations/test_appearance_generator.rb +63 -0
- data/test/hexapdf/type/annotations/test_ink.rb +31 -0
- data/test/hexapdf/type/test_font_type3.rb +4 -0
- metadata +26 -2
|
@@ -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-2026 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-2026 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/font_loader.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-2026 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
|
|
@@ -45,6 +45,53 @@ module HexaPDF
|
|
|
45
45
|
# needs to be usable by the PDF canvas. See below for details.
|
|
46
46
|
#
|
|
47
47
|
#
|
|
48
|
+
# == Available Font Loaders
|
|
49
|
+
#
|
|
50
|
+
# The following font loaders are available:
|
|
51
|
+
#
|
|
52
|
+
# HexaPDF::FontLoader::Standard14::
|
|
53
|
+
# This one makes the standard 14 PDF fonts (Helvetica in variants none, italic, bold and bold
|
|
54
|
+
# italic; Times in variants none, italic, bold and bold italic; Symbol; and ZapfDingbats)
|
|
55
|
+
# available.
|
|
56
|
+
#
|
|
57
|
+
# Usage:
|
|
58
|
+
#
|
|
59
|
+
# canvas.font('Times', variant: :bold)
|
|
60
|
+
#
|
|
61
|
+
# HexaPDF::FontLoader::FromFile::
|
|
62
|
+
# Interprets the font name as filename and tries to load the font from there. In this case a
|
|
63
|
+
# +:variant+ argument cannot be used as the font file is directly specified.
|
|
64
|
+
#
|
|
65
|
+
# Usage:
|
|
66
|
+
#
|
|
67
|
+
# canvas.font('/usr/share/fonts/truetype/hack/Hack-Regular.ttf')
|
|
68
|
+
#
|
|
69
|
+
# HexaPDF::FontLoader::VariantFromName:
|
|
70
|
+
# This one doesn't really load a font itself but makes it possible to append the variant name
|
|
71
|
+
# to the font name. So it resolves e.g. 'Times bold' to the font 'Times' in variant :bold.
|
|
72
|
+
#
|
|
73
|
+
# Usage:
|
|
74
|
+
#
|
|
75
|
+
# canvas.font('Times bold')
|
|
76
|
+
#
|
|
77
|
+
# HexaPDF::FontLoader::FromConfiguration
|
|
78
|
+
# This font loader defers to FromFile when loading the actual fonts. It allows defining font
|
|
79
|
+
# mappings using the configuration option 'font.map' where a font name is mapped to a hash
|
|
80
|
+
# that maps variant names to font file names.
|
|
81
|
+
#
|
|
82
|
+
# Usage:
|
|
83
|
+
#
|
|
84
|
+
# doc.config['font.map'] = {
|
|
85
|
+
# 'Hack' => {
|
|
86
|
+
# none: '/usr/share/fonts/ttf/Hack-Regular.ttf',
|
|
87
|
+
# bold: '/usr/share/fonts/ttf/Hack-Bold.ttf',
|
|
88
|
+
# italic: '/usr/share/fonts/ttf/Hack-Italic.ttf',
|
|
89
|
+
# bold_italic: '/usr/share/fonts/ttf/Hack-BoldItalic.ttf',
|
|
90
|
+
# },
|
|
91
|
+
# }
|
|
92
|
+
# canvas.font('Hack', variant: :italic)
|
|
93
|
+
#
|
|
94
|
+
#
|
|
48
95
|
# == Implementation of a Font Loader
|
|
49
96
|
#
|
|
50
97
|
# Each font loader is a (stateless) object (normally a module) that has to be callable, i.e. it
|
|
@@ -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-2026 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-2026 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-2026 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/image_loader.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-2026 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/importer.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-2026 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/layout/box.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-2026 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-2026 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-2026 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-2026 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
|
|
@@ -163,15 +163,13 @@ module HexaPDF
|
|
|
163
163
|
@box_fitter = BoxFitter.new([my_frame])
|
|
164
164
|
children.each {|box| @box_fitter.fit(box) }
|
|
165
165
|
|
|
166
|
-
if @box_fitter.success?
|
|
166
|
+
if @box_fitter.success? || (!@box_fitter.fit_results.empty? && @splitable)
|
|
167
167
|
update_content_width do
|
|
168
168
|
result = @box_fitter.fit_results.max_by {|r| r.mask.x + r.mask.width }
|
|
169
169
|
children.empty? ? 0 : result.mask.x + result.mask.width - my_frame.left
|
|
170
170
|
end
|
|
171
171
|
update_content_height { @box_fitter.content_heights.max }
|
|
172
|
-
fit_result.success!
|
|
173
|
-
elsif !@box_fitter.fit_results.empty? && @splitable
|
|
174
|
-
fit_result.overflow!
|
|
172
|
+
@box_fitter.success? ? fit_result.success! : fit_result.overflow!
|
|
175
173
|
end
|
|
176
174
|
end
|
|
177
175
|
|
data/lib/hexapdf/layout/frame.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-2026 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-2026 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-2026 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/layout/line.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-2026 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-2026 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-2026 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-2026 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/layout/style.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-2026 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
|
|
@@ -811,18 +811,76 @@ module HexaPDF
|
|
|
811
811
|
# font_features(features = nil)
|
|
812
812
|
#
|
|
813
813
|
# The font features (e.g. kerning, ligatures, ...) that should be applied by the shaping
|
|
814
|
-
# engine, defaults to {} (i.e. no font features are applied).
|
|
814
|
+
# engine, defaults to the empty hash {} (i.e. no font features are applied).
|
|
815
815
|
#
|
|
816
|
-
# Each feature
|
|
816
|
+
# Each feature can either be activated using `true` as value, deactivated using `false` as
|
|
817
|
+
# value or set to a specific mode using an integer. What is actually supported depends on the
|
|
818
|
+
# used shaping engine.
|
|
817
819
|
#
|
|
818
|
-
# See:
|
|
820
|
+
# See: #shaping_engine
|
|
819
821
|
#
|
|
820
822
|
# Examples:
|
|
821
823
|
#
|
|
822
824
|
# #>pdf-composer100
|
|
823
825
|
# composer.style(:base, font: ["Times", custom_encoding: true], font_size: 30)
|
|
824
826
|
# composer.text("Test flight")
|
|
825
|
-
# composer.text("Test flight", font_features: {kern: true, liga:
|
|
827
|
+
# composer.text("Test flight", font_features: {kern: true, liga: false})
|
|
828
|
+
|
|
829
|
+
##
|
|
830
|
+
# :method: font_script
|
|
831
|
+
# :call-seq:
|
|
832
|
+
# font_script(script = nil)
|
|
833
|
+
#
|
|
834
|
+
# The script in which the text is written, defaults to +nil+.
|
|
835
|
+
#
|
|
836
|
+
# This is used by the shaping engine to select the correct shaping implementation. If not set,
|
|
837
|
+
# the script is guessed from the text.
|
|
838
|
+
#
|
|
839
|
+
# See: #shaping_engine
|
|
840
|
+
|
|
841
|
+
##
|
|
842
|
+
# :method: language
|
|
843
|
+
# :call-seq:
|
|
844
|
+
# language(lang = nil)
|
|
845
|
+
#
|
|
846
|
+
# The language in which the text is written, defaults to +nil+.
|
|
847
|
+
#
|
|
848
|
+
# This is used, for example, by the shaping engine to correctly shape the text.
|
|
849
|
+
#
|
|
850
|
+
# See: #shaping_engine
|
|
851
|
+
|
|
852
|
+
##
|
|
853
|
+
# :method: direction
|
|
854
|
+
# :call-seq:
|
|
855
|
+
# direction(dir = nil)
|
|
856
|
+
#
|
|
857
|
+
# The direction of text, defaults to +:ltr+ (possible values are +:ltr+ and +:rtl+).
|
|
858
|
+
#
|
|
859
|
+
# This is used by the shaping engine to correctly shape the text.
|
|
860
|
+
#
|
|
861
|
+
# See: #shaping_engine
|
|
862
|
+
|
|
863
|
+
##
|
|
864
|
+
# :method: shaping_engine
|
|
865
|
+
# :call-seq:
|
|
866
|
+
# shaping_engine(engine = nil)
|
|
867
|
+
#
|
|
868
|
+
# The shaping engine that should be used, defaults to +:internal+. The other possible value is
|
|
869
|
+
# +:harfbuzz+.
|
|
870
|
+
#
|
|
871
|
+
# When set to +:harfbuzz+, the Rubygem +harfbuzz-ruby+ needs to be installed. If it is not
|
|
872
|
+
# available, HexaPDF will raise an error.
|
|
873
|
+
#
|
|
874
|
+
# See: HexaPDF::Layout::TextShaper for details.
|
|
875
|
+
#
|
|
876
|
+
# Examples:
|
|
877
|
+
#
|
|
878
|
+
# #>pdf-composer100
|
|
879
|
+
# composer.style(:base, font: 'Inter')
|
|
880
|
+
# composer.text("Incoming WAVE!")
|
|
881
|
+
# composer.formatted_text(["Incoming WAVE!",
|
|
882
|
+
# {text: " Take Cover!", font_features: {ss06: true}}],
|
|
883
|
+
# shaping_engine: :harfbuzz)
|
|
826
884
|
|
|
827
885
|
##
|
|
828
886
|
# :method: text_rendering_mode
|
|
@@ -1541,6 +1599,10 @@ module HexaPDF
|
|
|
1541
1599
|
[:horizontal_scaling, 100],
|
|
1542
1600
|
[:text_rise, 0],
|
|
1543
1601
|
[:font_features, {}],
|
|
1602
|
+
[:font_script, nil],
|
|
1603
|
+
[:language, nil],
|
|
1604
|
+
[:direction, :ltr, {valid_values: [:ltr, :rtl]}],
|
|
1605
|
+
[:shaping_engine, :internal, {valid_values: [:internal, :harfbuzz]}],
|
|
1544
1606
|
[:text_rendering_mode, "Content::TextRenderingMode::FILL",
|
|
1545
1607
|
{setter: "Content::TextRenderingMode.normalize(value)"}],
|
|
1546
1608
|
[:subscript, false,
|
|
@@ -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-2026 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
|
|
@@ -108,6 +108,17 @@ module HexaPDF
|
|
|
108
108
|
# [layout.text('E'), layout.text('F')]]
|
|
109
109
|
# composer.column(height: 50) {|col| col.table(cells) }
|
|
110
110
|
#
|
|
111
|
+
# If a cell doesn't completely fit, it is split. Non-split cells in the same continuation row
|
|
112
|
+
# retain their style but are empty:
|
|
113
|
+
#
|
|
114
|
+
# #>pdf-composer
|
|
115
|
+
# cells = [[layout.text('A'), layout.text('B')],
|
|
116
|
+
# [layout.text('C'), layout.text("D1\nD2")],
|
|
117
|
+
# [layout.text('E'), layout.text('F')]]
|
|
118
|
+
# composer.column(height: 50) {|col| col.table(cells) }
|
|
119
|
+
#
|
|
120
|
+
# Note that the above is only true for cells in rows that are not part of a row-span.
|
|
121
|
+
#
|
|
111
122
|
# It is also possible to use row and column spans:
|
|
112
123
|
#
|
|
113
124
|
# #>pdf-composer
|
|
@@ -237,6 +248,7 @@ module HexaPDF
|
|
|
237
248
|
|
|
238
249
|
# Fits the children of the table cell into the given rectangular area.
|
|
239
250
|
def fit_content(available_width, available_height, frame)
|
|
251
|
+
@remaining_boxes = nil
|
|
240
252
|
width = available_width - reserved_width
|
|
241
253
|
height = @used_height = available_height - reserved_height
|
|
242
254
|
return if width <= 0 || height <= 0
|
|
@@ -245,21 +257,27 @@ module HexaPDF
|
|
|
245
257
|
case children
|
|
246
258
|
when Box
|
|
247
259
|
child_result = frame.fit(children)
|
|
248
|
-
if child_result.
|
|
260
|
+
box, @remaining_boxes = children.split if child_result.overflow?
|
|
261
|
+
if child_result.success? || box
|
|
249
262
|
@preferred_width = child_result.x + child_result.box.width + reserved_width
|
|
250
263
|
@height = @preferred_height = child_result.box.height + reserved_height
|
|
251
264
|
@fit_results = [child_result]
|
|
252
|
-
fit_result.success!
|
|
265
|
+
box ? fit_result.overflow! : fit_result.success!
|
|
253
266
|
end
|
|
254
267
|
when Array
|
|
255
268
|
box_fitter = BoxFitter.new([frame])
|
|
256
269
|
children.each {|box| box_fitter.fit(box) }
|
|
257
|
-
if box_fitter.success?
|
|
270
|
+
if box_fitter.success? || !box_fitter.fit_results.empty?
|
|
258
271
|
max_x_result = box_fitter.fit_results.max_by {|result| result.x + result.box.width }
|
|
259
272
|
@preferred_width = max_x_result.x + max_x_result.box.width + reserved_width
|
|
260
273
|
@height = @preferred_height = box_fitter.content_heights[0] + reserved_height
|
|
261
274
|
@fit_results = box_fitter.fit_results
|
|
262
|
-
|
|
275
|
+
if box_fitter.success?
|
|
276
|
+
fit_result.success!
|
|
277
|
+
else
|
|
278
|
+
@remaining_boxes = box_fitter.remaining_boxes
|
|
279
|
+
fit_result.overflow!
|
|
280
|
+
end
|
|
263
281
|
end
|
|
264
282
|
else
|
|
265
283
|
@preferred_width = reserved_width
|
|
@@ -274,6 +292,14 @@ module HexaPDF
|
|
|
274
292
|
end
|
|
275
293
|
end
|
|
276
294
|
|
|
295
|
+
# Splits the content of the cell.
|
|
296
|
+
def split_content
|
|
297
|
+
box = create_split_box
|
|
298
|
+
box.instance_variable_set(:@children, @remaining_boxes)
|
|
299
|
+
box.instance_variable_set(:@remaining_boxes, nil)
|
|
300
|
+
[self, box]
|
|
301
|
+
end
|
|
302
|
+
|
|
277
303
|
# Draws the content of the cell.
|
|
278
304
|
def draw_content(canvas, x, y)
|
|
279
305
|
return if @fit_results.empty?
|
|
@@ -363,7 +389,7 @@ module HexaPDF
|
|
|
363
389
|
# Note that the same cell instance may be returned for different (row, column) arguments if
|
|
364
390
|
# the cell spans more than one row and/or column.
|
|
365
391
|
def [](row, column)
|
|
366
|
-
@cells[row]&.[](column)
|
|
392
|
+
row == @overridden_row_index ? @overridden_row_cells[column] : @cells[row]&.[](column)
|
|
367
393
|
end
|
|
368
394
|
|
|
369
395
|
# Returns the number of rows.
|
|
@@ -378,7 +404,15 @@ module HexaPDF
|
|
|
378
404
|
|
|
379
405
|
# Iterates over each row.
|
|
380
406
|
def each_row(&block)
|
|
381
|
-
|
|
407
|
+
return to_enum(__method__) unless block_given?
|
|
408
|
+
|
|
409
|
+
if @overridden_row_index
|
|
410
|
+
@cells[0...@overridden_row_index].each(&block)
|
|
411
|
+
block&.call(@overridden_row_cells)
|
|
412
|
+
@cells[(@overridden_row_index + 1)..-1].each(&block)
|
|
413
|
+
else
|
|
414
|
+
@cells.each(&block)
|
|
415
|
+
end
|
|
382
416
|
end
|
|
383
417
|
|
|
384
418
|
# Applies the given style properties to all cells and optionally yields all cells for more
|
|
@@ -409,12 +443,19 @@ module HexaPDF
|
|
|
409
443
|
row_heights = {}
|
|
410
444
|
zero_height_rows = {}
|
|
411
445
|
row_spans = []
|
|
446
|
+
split_row_cells = nil
|
|
412
447
|
|
|
413
448
|
@cells[start_row..-1].each.with_index(start_row) do |columns, row_index|
|
|
449
|
+
columns = @overridden_row_cells if row_index == @overridden_row_index
|
|
450
|
+
|
|
451
|
+
# Rows containing row-spanning cells aren't supported for cell-splitting
|
|
452
|
+
row_has_row_spans = columns.any? {|cell| cell.row != row_index || cell.row_span > 1 }
|
|
453
|
+
|
|
414
454
|
# 1. Fit all columns of the row and record the max height of all non-row-span cells. If
|
|
415
455
|
# a row has zero height (usually because it only has row-span cells), record that
|
|
416
456
|
# information. Additionally store all cells with row-spans.
|
|
417
457
|
row_fit = true
|
|
458
|
+
row_has_split_cells = false
|
|
418
459
|
row_height = 0
|
|
419
460
|
columns.each_with_index do |cell, col_index|
|
|
420
461
|
next if cell.row != row_index || cell.column != col_index
|
|
@@ -423,9 +464,14 @@ module HexaPDF
|
|
|
423
464
|
else
|
|
424
465
|
column_info[cell.column].last
|
|
425
466
|
end
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
467
|
+
cell_fit_result = cell.fit(available_cell_width, available_height, frame)
|
|
468
|
+
unless cell_fit_result.success?
|
|
469
|
+
if !row_has_row_spans && cell_fit_result.overflow?
|
|
470
|
+
row_has_split_cells = true
|
|
471
|
+
else
|
|
472
|
+
row_fit = false
|
|
473
|
+
break
|
|
474
|
+
end
|
|
429
475
|
end
|
|
430
476
|
if row_height < cell.preferred_height && cell.row_span == 1
|
|
431
477
|
row_height = cell.preferred_height
|
|
@@ -462,6 +508,11 @@ module HexaPDF
|
|
|
462
508
|
available_height -= cell.preferred_height - row_span_height
|
|
463
509
|
end
|
|
464
510
|
end
|
|
511
|
+
|
|
512
|
+
if row_has_split_cells
|
|
513
|
+
split_row_cells = create_split_row_cells(columns)
|
|
514
|
+
break
|
|
515
|
+
end
|
|
465
516
|
else
|
|
466
517
|
last_fitted_row_index = columns.min_by(&:row).row - 1 if height != available_height
|
|
467
518
|
break
|
|
@@ -473,6 +524,7 @@ module HexaPDF
|
|
|
473
524
|
# final height and top-left corner of each cell needs to be set.
|
|
474
525
|
running_height = 0
|
|
475
526
|
@cells[start_row..last_fitted_row_index].each.with_index(start_row) do |columns, row_index|
|
|
527
|
+
columns = @overridden_row_cells if row_index == @overridden_row_index
|
|
476
528
|
columns.each_with_index do |cell, col_index|
|
|
477
529
|
next if cell.row != row_index || cell.column != col_index
|
|
478
530
|
cell.left = column_info[cell.column].first
|
|
@@ -488,13 +540,15 @@ module HexaPDF
|
|
|
488
540
|
end
|
|
489
541
|
end
|
|
490
542
|
|
|
491
|
-
[height - available_height, last_fitted_row_index < start_row ? -1 : last_fitted_row_index
|
|
543
|
+
[height - available_height, last_fitted_row_index < start_row ? -1 : last_fitted_row_index,
|
|
544
|
+
split_row_cells]
|
|
492
545
|
end
|
|
493
546
|
|
|
494
547
|
# Draws the rows from +start_row+ to +end_row+ on the given +canvas+, with the top-left
|
|
495
548
|
# corner of the resulting table being at (+x+, +y+).
|
|
496
549
|
def draw_rows(start_row, end_row, canvas, x, y)
|
|
497
550
|
@cells[start_row..end_row].each.with_index(start_row) do |columns, row_index|
|
|
551
|
+
columns = @overridden_row_cells if row_index == @overridden_row_index
|
|
498
552
|
columns.each_with_index do |cell, col_index|
|
|
499
553
|
next if cell.row != row_index || cell.column != col_index
|
|
500
554
|
cell.draw(canvas, x + cell.left, y - cell.top - cell.height)
|
|
@@ -557,6 +611,22 @@ module HexaPDF
|
|
|
557
611
|
end
|
|
558
612
|
end
|
|
559
613
|
|
|
614
|
+
# Splits all cells in +columns+ and returns the new array.
|
|
615
|
+
def create_split_row_cells(columns)
|
|
616
|
+
columns.map.with_index do |cell, col_index|
|
|
617
|
+
next cell unless cell.column == col_index
|
|
618
|
+
_, split_box = cell.split
|
|
619
|
+
if split_box
|
|
620
|
+
split_box
|
|
621
|
+
else
|
|
622
|
+
# Create an empty clone of the fully fit cell
|
|
623
|
+
empty_cell = cell.send(:create_split_box)
|
|
624
|
+
empty_cell.instance_variable_set(:@children, nil)
|
|
625
|
+
empty_cell
|
|
626
|
+
end
|
|
627
|
+
end
|
|
628
|
+
end
|
|
629
|
+
|
|
560
630
|
end
|
|
561
631
|
|
|
562
632
|
# The Cells instance containing the data of the table.
|
|
@@ -682,6 +752,7 @@ module HexaPDF
|
|
|
682
752
|
@special_cells_fit_not_successful = false
|
|
683
753
|
[@header_cells, @footer_cells].each do |special_cells|
|
|
684
754
|
next unless special_cells
|
|
755
|
+
# Ignore split-cells (3rd result element) as not fully-fit headers/footers lead to failure
|
|
685
756
|
special_used_height, last_fitted_row_index = special_cells.fit_rows(0, height, columns, frame)
|
|
686
757
|
height -= special_used_height
|
|
687
758
|
used_height += special_used_height
|
|
@@ -689,13 +760,14 @@ module HexaPDF
|
|
|
689
760
|
return nil if @special_cells_fit_not_successful
|
|
690
761
|
end
|
|
691
762
|
|
|
692
|
-
main_used_height, @last_fitted_row_index
|
|
763
|
+
main_used_height, @last_fitted_row_index, @split_row_cells =
|
|
764
|
+
@cells.fit_rows(@start_row_index, height, columns, frame)
|
|
693
765
|
used_height += main_used_height
|
|
694
766
|
|
|
695
767
|
update_content_width { columns[-1].sum + rw }
|
|
696
768
|
update_content_height { used_height + rh }
|
|
697
769
|
|
|
698
|
-
if @last_fitted_row_index == @cells.number_of_rows - 1
|
|
770
|
+
if @last_fitted_row_index == @cells.number_of_rows - 1 && !@split_row_cells
|
|
699
771
|
fit_result.success!
|
|
700
772
|
elsif @last_fitted_row_index >= 0
|
|
701
773
|
fit_result.overflow!
|
|
@@ -724,8 +796,19 @@ module HexaPDF
|
|
|
724
796
|
# Splits the content of the table box. This method is called from Box#split.
|
|
725
797
|
def split_content
|
|
726
798
|
box = create_split_box
|
|
727
|
-
|
|
799
|
+
|
|
800
|
+
if @split_row_cells
|
|
801
|
+
cells = @cells.clone
|
|
802
|
+
cells.instance_variable_set(:@overridden_row_cells, @split_row_cells)
|
|
803
|
+
cells.instance_variable_set(:@overridden_row_index, @last_fitted_row_index)
|
|
804
|
+
box.instance_variable_set(:@cells, cells)
|
|
805
|
+
box.instance_variable_set(:@start_row_index, @last_fitted_row_index)
|
|
806
|
+
else
|
|
807
|
+
box.instance_variable_set(:@start_row_index, @last_fitted_row_index + 1)
|
|
808
|
+
end
|
|
809
|
+
|
|
728
810
|
box.instance_variable_set(:@last_fitted_row_index, -1)
|
|
811
|
+
box.instance_variable_set(:@split_row_cells, nil)
|
|
729
812
|
box.instance_variable_set(:@special_cells_fit_not_successful, nil)
|
|
730
813
|
header_cells = @header ? Cells.new(@header.call(self), cell_style: @cell_style) : nil
|
|
731
814
|
box.instance_variable_set(:@header_cells, header_cells)
|
|
@@ -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-2026 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
|