hexapdf 0.46.0 → 1.6.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 +342 -16
- data/LICENSE +1 -1
- data/README.md +9 -8
- data/examples/009-text_layouter_alignment.rb +4 -0
- data/examples/010-text_layouter_inline_boxes.rb +4 -0
- data/examples/011-text_layouter_line_wrapping.rb +4 -0
- data/examples/012-text_layouter_styling.rb +9 -4
- data/examples/013-text_layouter_shapes.rb +5 -0
- data/examples/015-boxes.rb +3 -0
- data/examples/016-frame_automatic_box_placement.rb +3 -0
- data/examples/017-frame_text_flow.rb +3 -0
- data/examples/022-outline.rb +5 -1
- data/examples/{028-frame_mask_mode.rb → 028-composer_mask_mode.rb} +3 -3
- data/lib/hexapdf/cli/batch.rb +1 -1
- data/lib/hexapdf/cli/command.rb +65 -65
- data/lib/hexapdf/cli/debug_info.rb +98 -0
- data/lib/hexapdf/cli/files.rb +1 -1
- data/lib/hexapdf/cli/fonts.rb +1 -1
- data/lib/hexapdf/cli/form.rb +11 -6
- data/lib/hexapdf/cli/image2pdf.rb +1 -1
- data/lib/hexapdf/cli/images.rb +19 -4
- data/lib/hexapdf/cli/info.rb +1 -1
- data/lib/hexapdf/cli/inspect.rb +24 -8
- data/lib/hexapdf/cli/merge.rb +1 -1
- data/lib/hexapdf/cli/modify.rb +1 -2
- data/lib/hexapdf/cli/optimize.rb +6 -6
- 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 +20 -2
- data/lib/hexapdf/composer.rb +22 -1
- data/lib/hexapdf/configuration.rb +56 -1
- 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 +2 -2
- data/lib/hexapdf/content/operator.rb +1 -1
- data/lib/hexapdf/content/parser.rb +22 -23
- data/lib/hexapdf/content/processor.rb +1 -1
- 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 +8 -2
- data/lib/hexapdf/dictionary_fields.rb +2 -2
- data/lib/hexapdf/digital_signature/cms_handler.rb +19 -2
- 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 +2 -2
- data/lib/hexapdf/digital_signature/signatures.rb +1 -1
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +3 -3
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -2
- data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +25 -5
- 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 +220 -0
- 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 +95 -16
- data/lib/hexapdf/document/metadata.rb +11 -4
- data/lib/hexapdf/document/pages.rb +1 -1
- data/lib/hexapdf/document.rb +52 -9
- data/lib/hexapdf/encryption/aes.rb +1 -1
- data/lib/hexapdf/encryption/arc4.rb +3 -3
- 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 +4 -2
- data/lib/hexapdf/encryption/standard_security_handler.rb +40 -29
- data/lib/hexapdf/encryption.rb +1 -1
- data/lib/hexapdf/error.rb +12 -4
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_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 +59 -5
- data/lib/hexapdf/font/cmap.rb +18 -7
- data/lib/hexapdf/font/encoding/base.rb +28 -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 +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/table.rb +7 -2
- data/lib/hexapdf/font/true_type.rb +1 -1
- data/lib/hexapdf/font/true_type_wrapper.rb +51 -16
- 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 +3 -4
- 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/font_loader/variant_from_name.rb +1 -1
- data/lib/hexapdf/font_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/image_loader.rb +1 -1
- data/lib/hexapdf/importer.rb +2 -2
- data/lib/hexapdf/layout/box.rb +6 -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 +64 -29
- 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 +133 -22
- data/lib/hexapdf/layout/table_box.rb +86 -14
- data/lib/hexapdf/layout/text_box.rb +1 -1
- data/lib/hexapdf/layout/text_fragment.rb +13 -2
- 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/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 +4 -4
- data/lib/hexapdf/parser.rb +36 -7
- data/lib/hexapdf/pdf_array.rb +26 -4
- data/lib/hexapdf/rectangle.rb +1 -1
- data/lib/hexapdf/reference.rb +2 -2
- data/lib/hexapdf/revision.rb +7 -3
- data/lib/hexapdf/revisions.rb +1 -1
- data/lib/hexapdf/serializer.rb +8 -8
- data/lib/hexapdf/stream.rb +1 -1
- data/lib/hexapdf/task/dereference.rb +1 -1
- data/lib/hexapdf/task/merge_acro_form.rb +164 -0
- data/lib/hexapdf/task/optimize.rb +5 -5
- data/lib/hexapdf/task/pdfa.rb +1 -1
- data/lib/hexapdf/task.rb +2 -1
- data/lib/hexapdf/test_utils.rb +3 -2
- data/lib/hexapdf/tokenizer.rb +52 -44
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +66 -13
- 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 +6 -2
- data/lib/hexapdf/type/acro_form/form.rb +23 -32
- data/lib/hexapdf/type/acro_form/java_script_actions.rb +10 -3
- data/lib/hexapdf/type/acro_form/signature_field.rb +19 -8
- data/lib/hexapdf/type/acro_form/text_field.rb +10 -3
- data/lib/hexapdf/type/acro_form/variable_text_field.rb +13 -5
- 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 +2 -1
- data/lib/hexapdf/type/actions/go_to_r.rb +2 -1
- data/lib/hexapdf/type/actions/launch.rb +6 -2
- 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 +78 -3
- data/lib/hexapdf/type/annotations/appearance_generator.rb +426 -0
- data/lib/hexapdf/type/annotations/border_effect.rb +99 -0
- data/lib/hexapdf/type/annotations/border_styling.rb +160 -0
- data/lib/hexapdf/type/annotations/circle.rb +65 -0
- data/lib/hexapdf/type/annotations/interior_color.rb +84 -0
- data/lib/hexapdf/type/annotations/line.rb +334 -0
- data/lib/hexapdf/type/annotations/line_ending_styling.rb +208 -0
- data/lib/hexapdf/type/annotations/link.rb +1 -1
- data/lib/hexapdf/type/annotations/markup_annotation.rb +15 -3
- data/lib/hexapdf/type/annotations/polygon.rb +64 -0
- data/lib/hexapdf/type/annotations/polygon_polyline.rb +109 -0
- data/lib/hexapdf/type/annotations/polyline.rb +64 -0
- data/lib/hexapdf/type/annotations/square.rb +65 -0
- data/lib/hexapdf/type/annotations/square_circle.rb +77 -0
- data/lib/hexapdf/type/annotations/text.rb +1 -1
- data/lib/hexapdf/type/annotations/widget.rb +56 -118
- data/lib/hexapdf/type/annotations.rb +13 -1
- data/lib/hexapdf/type/catalog.rb +5 -2
- data/lib/hexapdf/type/cid_font.rb +6 -3
- data/lib/hexapdf/type/cmap.rb +58 -0
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +18 -15
- data/lib/hexapdf/type/font.rb +1 -1
- data/lib/hexapdf/type/font_descriptor.rb +5 -4
- data/lib/hexapdf/type/font_simple.rb +4 -2
- data/lib/hexapdf/type/font_true_type.rb +3 -1
- data/lib/hexapdf/type/font_type0.rb +2 -2
- data/lib/hexapdf/type/font_type1.rb +19 -1
- data/lib/hexapdf/type/font_type3.rb +1 -2
- data/lib/hexapdf/type/form.rb +8 -5
- data/lib/hexapdf/type/graphics_state_parameter.rb +8 -5
- data/lib/hexapdf/type/icon_fit.rb +1 -1
- data/lib/hexapdf/type/image.rb +9 -5
- data/lib/hexapdf/type/info.rb +3 -3
- data/lib/hexapdf/type/mark_information.rb +3 -3
- data/lib/hexapdf/type/marked_content_reference.rb +59 -0
- data/lib/hexapdf/type/measure.rb +57 -0
- data/lib/hexapdf/type/metadata.rb +1 -1
- data/lib/hexapdf/type/names.rb +1 -1
- data/lib/hexapdf/type/namespace.rb +57 -0
- data/lib/hexapdf/type/object_reference.rb +57 -0
- data/lib/hexapdf/type/object_stream.rb +1 -1
- data/lib/hexapdf/type/optional_content_configuration.rb +2 -2
- data/lib/hexapdf/type/optional_content_group.rb +1 -1
- data/lib/hexapdf/type/optional_content_membership.rb +2 -2
- 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 +6 -4
- 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 +13 -9
- data/lib/hexapdf/type/struct_elem.rb +72 -0
- data/lib/hexapdf/type/struct_tree_root.rb +64 -0
- data/lib/hexapdf/type/trailer.rb +1 -1
- data/lib/hexapdf/type/viewer_preferences.rb +5 -4
- data/lib/hexapdf/type/xref_stream.rb +1 -1
- data/lib/hexapdf/type.rb +8 -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 +17 -4
- data/lib/hexapdf/utils.rb +1 -1
- data/lib/hexapdf/version.rb +2 -2
- data/lib/hexapdf/writer.rb +3 -2
- data/lib/hexapdf/xref_section.rb +25 -6
- data/lib/hexapdf.rb +1 -1
- data/test/data/standard-security-handler/bothpwd-aes-256bit-V5-R5.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-aes-256bit-V5-R5.pdf +44 -0
- data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5-R5.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-aes-256bit-V5-R5.pdf +0 -0
- data/test/hexapdf/common_tokenizer_tests.rb +7 -7
- data/test/hexapdf/content/test_graphics_state.rb +2 -3
- data/test/hexapdf/content/test_operator.rb +4 -5
- data/test/hexapdf/digital_signature/common.rb +6 -1
- data/test/hexapdf/digital_signature/signing/test_default_handler.rb +6 -1
- data/test/hexapdf/digital_signature/signing/test_timestamp_handler.rb +12 -0
- data/test/hexapdf/digital_signature/test_cms_handler.rb +25 -15
- data/test/hexapdf/digital_signature/test_handler.rb +2 -3
- data/test/hexapdf/digital_signature/test_pkcs1_handler.rb +1 -2
- data/test/hexapdf/digital_signature/test_signature.rb +7 -0
- data/test/hexapdf/digital_signature/test_signatures.rb +12 -7
- data/test/hexapdf/document/test_annotations.rb +75 -0
- data/test/hexapdf/document/test_layout.rb +38 -10
- data/test/hexapdf/document/test_metadata.rb +13 -1
- data/test/hexapdf/encryption/common.rb +1 -1
- data/test/hexapdf/encryption/test_aes.rb +1 -1
- data/test/hexapdf/encryption/test_arc4.rb +2 -2
- data/test/hexapdf/encryption/test_security_handler.rb +8 -6
- data/test/hexapdf/encryption/test_standard_security_handler.rb +7 -3
- data/test/hexapdf/filter/test_ascii85_decode.rb +1 -1
- data/test/hexapdf/filter/test_ascii_hex_decode.rb +1 -1
- data/test/hexapdf/filter/test_flate_decode.rb +2 -3
- data/test/hexapdf/font/cmap/test_writer.rb +73 -16
- data/test/hexapdf/font/encoding/test_base.rb +20 -0
- data/test/hexapdf/font/encoding/test_glyph_list.rb +1 -1
- data/test/hexapdf/font/test_true_type_wrapper.rb +31 -5
- data/test/hexapdf/font/test_type1_wrapper.rb +8 -1
- data/test/hexapdf/font/true_type/test_table.rb +12 -0
- data/test/hexapdf/layout/test_box.rb +8 -2
- data/test/hexapdf/layout/test_container_box.rb +34 -6
- data/test/hexapdf/layout/test_list_box.rb +7 -7
- data/test/hexapdf/layout/test_page_style.rb +1 -1
- data/test/hexapdf/layout/test_style.rb +46 -12
- data/test/hexapdf/layout/test_table_box.rb +66 -16
- data/test/hexapdf/layout/test_text_box.rb +0 -6
- data/test/hexapdf/layout/test_text_fragment.rb +3 -3
- data/test/hexapdf/layout/test_text_layouter.rb +4 -2
- data/test/hexapdf/task/test_merge_acro_form.rb +104 -0
- data/test/hexapdf/task/test_optimize.rb +3 -1
- data/test/hexapdf/test_composer.rb +15 -0
- data/test/hexapdf/test_dictionary.rb +15 -0
- data/test/hexapdf/test_dictionary_fields.rb +1 -0
- data/test/hexapdf/test_document.rb +26 -8
- data/test/hexapdf/test_filter.rb +1 -1
- data/test/hexapdf/test_importer.rb +7 -0
- data/test/hexapdf/test_object.rb +1 -1
- data/test/hexapdf/test_parser.rb +87 -18
- data/test/hexapdf/test_pdf_array.rb +36 -3
- data/test/hexapdf/test_revision.rb +27 -6
- data/test/hexapdf/test_revisions.rb +1 -1
- data/test/hexapdf/test_serializer.rb +4 -4
- data/test/hexapdf/test_stream.rb +1 -2
- data/test/hexapdf/test_tokenizer.rb +1 -1
- data/test/hexapdf/test_writer.rb +22 -8
- data/test/hexapdf/test_xref_section.rb +15 -0
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +118 -26
- data/test/hexapdf/type/acro_form/test_button_field.rb +7 -6
- data/test/hexapdf/type/acro_form/test_field.rb +10 -0
- data/test/hexapdf/type/acro_form/test_form.rb +32 -9
- data/test/hexapdf/type/acro_form/test_java_script_actions.rb +21 -0
- data/test/hexapdf/type/acro_form/test_signature_field.rb +3 -1
- data/test/hexapdf/type/acro_form/test_text_field.rb +7 -1
- data/test/hexapdf/type/acro_form/test_variable_text_field.rb +14 -1
- data/test/hexapdf/type/actions/test_launch.rb +6 -2
- data/test/hexapdf/type/annotations/test_appearance_generator.rb +608 -0
- data/test/hexapdf/type/annotations/test_border_effect.rb +59 -0
- data/test/hexapdf/type/annotations/test_border_styling.rb +114 -0
- data/test/hexapdf/type/annotations/test_interior_color.rb +37 -0
- data/test/hexapdf/type/annotations/test_line.rb +144 -0
- data/test/hexapdf/type/annotations/test_line_ending_styling.rb +42 -0
- data/test/hexapdf/type/annotations/test_polygon_polyline.rb +29 -0
- data/test/hexapdf/type/annotations/test_widget.rb +47 -81
- data/test/hexapdf/type/test_annotation.rb +58 -0
- data/test/hexapdf/type/test_font_type1.rb +20 -1
- data/test/hexapdf/type/test_form.rb +7 -1
- data/test/hexapdf/type/test_image.rb +1 -1
- data/test/hexapdf/type/test_page.rb +7 -1
- data/test/hexapdf/type/test_page_tree_node.rb +2 -2
- data/test/hexapdf/type/test_resources.rb +3 -1
- data/test/hexapdf/utils/test_sorted_tree_node.rb +18 -7
- data/test/test_helper.rb +7 -0
- metadata +69 -9
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-2025 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
|
|
@@ -150,14 +150,15 @@ module HexaPDF
|
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
# :call-seq:
|
|
153
|
-
# quad.set(value)
|
|
154
|
-
# quad.set(array)
|
|
155
|
-
# quad.set(quad
|
|
153
|
+
# quad.set(value) -> quad
|
|
154
|
+
# quad.set(array) -> quad
|
|
155
|
+
# quad.set(hash) -> quad
|
|
156
|
+
# quad.set(quad) -> quad
|
|
156
157
|
#
|
|
157
|
-
# Sets all values of the quad.
|
|
158
|
+
# Sets all values of the quad and returns it.
|
|
158
159
|
#
|
|
159
|
-
# * If a single value is provided that is neither a Quad nor an array, it is
|
|
160
|
-
# an array with one value was given.
|
|
160
|
+
# * If a single value is provided that is neither a Quad nor an array nor a hash, it is
|
|
161
|
+
# handled as if an array with one value was given.
|
|
161
162
|
#
|
|
162
163
|
# * If a Quad is provided, its values are used.
|
|
163
164
|
#
|
|
@@ -170,6 +171,9 @@ module HexaPDF
|
|
|
170
171
|
# third value.
|
|
171
172
|
# * Four or more values: Top is set to the first, right to the second, bottom to the third
|
|
172
173
|
# and left to the fourth value.
|
|
174
|
+
#
|
|
175
|
+
# * If a hash is provided, the keys +:top+, +:bottom+, +:left+ and +:right+ are used to set
|
|
176
|
+
# the respective value. All unspecified keys that have not been set before are set to 0.
|
|
173
177
|
def set(obj)
|
|
174
178
|
case obj
|
|
175
179
|
when Quad
|
|
@@ -182,9 +186,15 @@ module HexaPDF
|
|
|
182
186
|
@bottom = obj[2] || obj[0]
|
|
183
187
|
@left = obj[3] || obj[1] || obj[0]
|
|
184
188
|
@right = obj[1] || obj[0]
|
|
189
|
+
when Hash
|
|
190
|
+
@top = obj[:top] || @top || 0
|
|
191
|
+
@bottom = obj[:bottom] || @bottom || 0
|
|
192
|
+
@left = obj[:left] || @left || 0
|
|
193
|
+
@right = obj[:right] || @right || 0
|
|
185
194
|
else
|
|
186
195
|
@top = @bottom = @left = @right = obj
|
|
187
196
|
end
|
|
197
|
+
self
|
|
188
198
|
end
|
|
189
199
|
|
|
190
200
|
# Returns +true+ if the quad effectively contains only one value.
|
|
@@ -265,7 +275,9 @@ module HexaPDF
|
|
|
265
275
|
miter_limit(10).
|
|
266
276
|
line_cap_style(line_cap_style(:top))
|
|
267
277
|
|
|
268
|
-
|
|
278
|
+
if width.top > w || width.top > h
|
|
279
|
+
canvas.rectangle(x, y, w, h).clip_path.end_path
|
|
280
|
+
end
|
|
269
281
|
if style.top == :solid
|
|
270
282
|
canvas.line_dash_pattern(0).
|
|
271
283
|
rectangle(x + offset, y + offset, w - 2 * offset, h - 2 * offset).stroke
|
|
@@ -396,6 +408,9 @@ module HexaPDF
|
|
|
396
408
|
# bottom-left corner of the box during the drawing operations.
|
|
397
409
|
class Layers
|
|
398
410
|
|
|
411
|
+
# The array holding all raw layer definitions.
|
|
412
|
+
attr_reader :layers
|
|
413
|
+
|
|
399
414
|
# Creates a new Layers object popuplated with the given +layers+.
|
|
400
415
|
def initialize(layers = nil)
|
|
401
416
|
@layers = []
|
|
@@ -601,11 +616,36 @@ module HexaPDF
|
|
|
601
616
|
# style.update(**properties) -> style
|
|
602
617
|
#
|
|
603
618
|
# Updates the style's properties using the key-value pairs specified by the +properties+ hash.
|
|
619
|
+
#
|
|
620
|
+
# Also see: #merge
|
|
604
621
|
def update(**properties)
|
|
605
622
|
properties.each {|key, value| send(key, value) }
|
|
606
623
|
self
|
|
607
624
|
end
|
|
608
625
|
|
|
626
|
+
# Yields all set properties.
|
|
627
|
+
def each_property # :yield: property, value
|
|
628
|
+
return to_enum(__method__) unless block_given?
|
|
629
|
+
instance_variables.each do |iv|
|
|
630
|
+
(val = PROPERTIES[iv]) && yield(val, instance_variable_get(iv))
|
|
631
|
+
end
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
# :call-seq:
|
|
635
|
+
# style.merge(other_style) -> style
|
|
636
|
+
#
|
|
637
|
+
# Merges the set properties of the +other_style+ object into this one.
|
|
638
|
+
#
|
|
639
|
+
# Note that merging is done on a per-property basis. So if a complex property is set on
|
|
640
|
+
# +other_style+ and also on +self+, the +other_style+ value completely overwrites the one from
|
|
641
|
+
# +self+.
|
|
642
|
+
#
|
|
643
|
+
# Also see: #update
|
|
644
|
+
def merge(other)
|
|
645
|
+
other.each_property {|property, value| send(property, value) }
|
|
646
|
+
self
|
|
647
|
+
end
|
|
648
|
+
|
|
609
649
|
##
|
|
610
650
|
# :method: font
|
|
611
651
|
# :call-seq:
|
|
@@ -613,8 +653,9 @@ module HexaPDF
|
|
|
613
653
|
#
|
|
614
654
|
# The font to be used, must be set to a valid font wrapper object before it can be used.
|
|
615
655
|
#
|
|
616
|
-
# HexaPDF::
|
|
617
|
-
# to a font wrapper object before doing
|
|
656
|
+
# HexaPDF::Document::Layout handles this property - together with #font_bold and #font_italic
|
|
657
|
+
# - specially in that it resolves a set string or array to a font wrapper object before doing
|
|
658
|
+
# anything else with the style object.
|
|
618
659
|
#
|
|
619
660
|
# This is the only style property without a default value!
|
|
620
661
|
#
|
|
@@ -631,6 +672,48 @@ module HexaPDF
|
|
|
631
672
|
# composer.text("Courier Bold", font: "Courier bold")
|
|
632
673
|
# composer.text("Courier Bold also", font: ["Courier", variant: :bold])
|
|
633
674
|
|
|
675
|
+
##
|
|
676
|
+
# :method: font_bold
|
|
677
|
+
# :call-seq:
|
|
678
|
+
# font_bold(bold = false)
|
|
679
|
+
#
|
|
680
|
+
# Specifies whether the bold variant of the font is used.
|
|
681
|
+
#
|
|
682
|
+
# Note that this property only has affect if #font is not already set to a font wrapper
|
|
683
|
+
# object and if it is set explicitly (i.e. #font_bold? returns +true+).
|
|
684
|
+
#
|
|
685
|
+
# See #font, #font_italic
|
|
686
|
+
#
|
|
687
|
+
# Examples:
|
|
688
|
+
#
|
|
689
|
+
# #>pdf-composer100
|
|
690
|
+
# composer.text("Helvetica bold", font: "Helvetica", font_bold: true)
|
|
691
|
+
#
|
|
692
|
+
# helvetica_bold = composer.document.fonts.add("Helvetica", variant: :bold)
|
|
693
|
+
# composer.text("Helvetica bold", font: helvetica_bold, font_bold: false)
|
|
694
|
+
# composer.text("Helvetica", font: ["Helvetica", {variant: :bold}], font_bold: false)
|
|
695
|
+
|
|
696
|
+
##
|
|
697
|
+
# :method: font_italic
|
|
698
|
+
# :call-seq:
|
|
699
|
+
# font_italic(bold = false)
|
|
700
|
+
#
|
|
701
|
+
# Specifies whether the italic variant of the font is used.
|
|
702
|
+
#
|
|
703
|
+
# Note that this property only has affect if #font is not already set to a font wrapper
|
|
704
|
+
# object and if it is set explicitly (i.e. #font_italic? returns +true+).
|
|
705
|
+
#
|
|
706
|
+
# See #font, #font_bold.
|
|
707
|
+
#
|
|
708
|
+
# Examples:
|
|
709
|
+
#
|
|
710
|
+
# #>pdf-composer100
|
|
711
|
+
# composer.text("Helvetica italic", font: "Helvetica", font_italic: true)
|
|
712
|
+
#
|
|
713
|
+
# helvetica_bold = composer.document.fonts.add("Helvetica", variant: :italic)
|
|
714
|
+
# composer.text("Helvetica italic", font: helvetica_bold, font_italic: false)
|
|
715
|
+
# composer.text("Helvetica", font: ["Helvetica", {variant: :italic}], font_italic: false)
|
|
716
|
+
|
|
634
717
|
##
|
|
635
718
|
# :method: font_size
|
|
636
719
|
# :call-seq:
|
|
@@ -1019,7 +1102,7 @@ module HexaPDF
|
|
|
1019
1102
|
#
|
|
1020
1103
|
# This method can set the line spacing in two ways:
|
|
1021
1104
|
#
|
|
1022
|
-
# * Using
|
|
1105
|
+
# * Using the positional, mandatory argument +type+ and the optional +value+.
|
|
1023
1106
|
# * Or a hash with the keys +type+ and +value+.
|
|
1024
1107
|
#
|
|
1025
1108
|
# Note that the last line has no additional spacing after it by default. Set #last_line_gap
|
|
@@ -1420,8 +1503,33 @@ module HexaPDF
|
|
|
1420
1503
|
# composer.text("This is some longer text that does not appear in two lines.",
|
|
1421
1504
|
# height: 15, overflow: :truncate)
|
|
1422
1505
|
|
|
1423
|
-
|
|
1506
|
+
##
|
|
1507
|
+
# :method: box_options
|
|
1508
|
+
# :call-seq:
|
|
1509
|
+
# box_options(**options)
|
|
1510
|
+
#
|
|
1511
|
+
# Contains initialization arguments for the box instance that is created with this
|
|
1512
|
+
# style. Together with the other style properties this allows the complete specification of a
|
|
1513
|
+
# box instance just via a Style instance.
|
|
1514
|
+
#
|
|
1515
|
+
# Note that this property is only used by the HexaPDF::Document::Layout methods when a box
|
|
1516
|
+
# instance is created. If a box instance is created directly, this property has no effect.
|
|
1517
|
+
#
|
|
1518
|
+
# Examples:
|
|
1519
|
+
#
|
|
1520
|
+
# #>pdf-composer100
|
|
1521
|
+
# composer.style(:my_list, box_options: {marker_type: :decimal, item_spacing: 15})
|
|
1522
|
+
# composer.list(style: :my_list) do |list|
|
|
1523
|
+
# list.text("This is some text.")
|
|
1524
|
+
# list.text("This is some other text.")
|
|
1525
|
+
# end
|
|
1526
|
+
|
|
1527
|
+
|
|
1528
|
+
# :nodoc:
|
|
1529
|
+
PROPERTIES = [
|
|
1424
1530
|
[:font, "raise HexaPDF::Error, 'No font set'"],
|
|
1531
|
+
[:font_bold, false],
|
|
1532
|
+
[:font_italic, false],
|
|
1425
1533
|
[:font_size, 10],
|
|
1426
1534
|
[:line_height, nil],
|
|
1427
1535
|
[:character_spacing, 0],
|
|
@@ -1432,10 +1540,10 @@ module HexaPDF
|
|
|
1432
1540
|
[:text_rendering_mode, "Content::TextRenderingMode::FILL",
|
|
1433
1541
|
{setter: "Content::TextRenderingMode.normalize(value)"}],
|
|
1434
1542
|
[:subscript, false,
|
|
1435
|
-
{setter: "value; superscript(false) if superscript",
|
|
1543
|
+
{setter: "value; superscript(false) if value && superscript? && superscript",
|
|
1436
1544
|
valid_values: [true, false]}],
|
|
1437
1545
|
[:superscript, false,
|
|
1438
|
-
{setter: "value; subscript(false) if subscript",
|
|
1546
|
+
{setter: "value; subscript(false) if value && subscript? && subscript",
|
|
1439
1547
|
valid_values: [true, false]}],
|
|
1440
1548
|
[:underline, false, {valid_values: [true, false]}],
|
|
1441
1549
|
[:strikeout, false, {valid_values: [true, false]}],
|
|
@@ -1455,15 +1563,17 @@ module HexaPDF
|
|
|
1455
1563
|
[:text_valign, :top, {valid_values: [:top, :center, :bottom]}],
|
|
1456
1564
|
[:text_indent, 0],
|
|
1457
1565
|
[:line_spacing, "LineSpacing.new(type: :single)",
|
|
1458
|
-
{setter: "LineSpacing.new(**(value.kind_of?(Symbol) || value.kind_of?(Numeric)
|
|
1459
|
-
"{type: value, value: extra_arg} : value))",
|
|
1566
|
+
{setter: "LineSpacing.new(**(value.kind_of?(Symbol) || value.kind_of?(Numeric) || " \
|
|
1567
|
+
"value.kind_of?(LineSpacing) ? {type: value, value: extra_arg} : value))",
|
|
1460
1568
|
extra_args: ", extra_arg = nil"}],
|
|
1461
1569
|
[:last_line_gap, false, {valid_values: [true, false]}],
|
|
1462
1570
|
[:fill_horizontal, nil],
|
|
1463
1571
|
[:background_color, nil],
|
|
1464
1572
|
[:background_alpha, 1],
|
|
1465
|
-
[:padding, "Quad.new(0)",
|
|
1466
|
-
|
|
1573
|
+
[:padding, "Quad.new(0)",
|
|
1574
|
+
{setter: "value.kind_of?(Hash) && @name ? @name.set(value) : Quad.new(value)"}],
|
|
1575
|
+
[:margin, "Quad.new(0)",
|
|
1576
|
+
{setter: "value.kind_of?(Hash) && @name ? @name.set(value) : Quad.new(value)"}],
|
|
1467
1577
|
[:border, "Border.new", {setter: "Border.new(**value)"}],
|
|
1468
1578
|
[:overlays, "Layers.new", {setter: "Layers.new(value)"}],
|
|
1469
1579
|
[:underlays, "Layers.new", {setter: "Layers.new(value)"}],
|
|
@@ -1473,6 +1583,7 @@ module HexaPDF
|
|
|
1473
1583
|
[:mask_mode, :default, {valid_values: [:default, :none, :box, :fill_horizontal,
|
|
1474
1584
|
:fill_frame_horizontal, :fill_vertical, :fill]}],
|
|
1475
1585
|
[:overflow, :error],
|
|
1586
|
+
[:box_options, {}],
|
|
1476
1587
|
].each do |name, default, options = {}|
|
|
1477
1588
|
default = default.inspect unless default.kind_of?(String)
|
|
1478
1589
|
setter = options.delete(:setter) || "value"
|
|
@@ -1498,7 +1609,7 @@ module HexaPDF
|
|
|
1498
1609
|
end
|
|
1499
1610
|
EOF
|
|
1500
1611
|
alias_method("#{name}=", name)
|
|
1501
|
-
end
|
|
1612
|
+
end.each_with_object({}) {|arr, hash| hash[:"@#{arr.first}"] = arr.first }
|
|
1502
1613
|
|
|
1503
1614
|
##
|
|
1504
1615
|
# :method: text_segmentation_algorithm
|
|
@@ -1545,9 +1656,9 @@ module HexaPDF
|
|
|
1545
1656
|
|
|
1546
1657
|
# The calculated text rise, taking superscript and subscript into account.
|
|
1547
1658
|
def calculated_text_rise
|
|
1548
|
-
if superscript
|
|
1659
|
+
if superscript? && superscript
|
|
1549
1660
|
text_rise + font_size * 0.33
|
|
1550
|
-
elsif subscript
|
|
1661
|
+
elsif subscript? && subscript
|
|
1551
1662
|
text_rise - font_size * 0.20
|
|
1552
1663
|
else
|
|
1553
1664
|
text_rise
|
|
@@ -1556,7 +1667,7 @@ module HexaPDF
|
|
|
1556
1667
|
|
|
1557
1668
|
# The calculated font size, taking superscript and subscript into account.
|
|
1558
1669
|
def calculated_font_size
|
|
1559
|
-
(superscript || subscript ? 0.583 : 1) * font_size
|
|
1670
|
+
((superscript? && superscript) || (subscript? && subscript) ? 0.583 : 1) * font_size
|
|
1560
1671
|
end
|
|
1561
1672
|
|
|
1562
1673
|
# Returns the correct offset from the baseline for the underline.
|
|
@@ -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-2025 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
|
|
@@ -85,6 +85,13 @@ module HexaPDF
|
|
|
85
85
|
# #>pdf-composer
|
|
86
86
|
# composer.table([['A', 'B'], ['C', 'D']])
|
|
87
87
|
#
|
|
88
|
+
# Each cell can hold zero or more boxes:
|
|
89
|
+
#
|
|
90
|
+
# #>pdf-composer
|
|
91
|
+
# cells = [[[layout.text('A'), layout.image(machu_picchu, height: 40)], layout.text('B')],
|
|
92
|
+
# [nil, layout.text('D')]]
|
|
93
|
+
# composer.table(cells)
|
|
94
|
+
#
|
|
88
95
|
# The style of the cells can be customized, e.g. to avoid drawing borders:
|
|
89
96
|
#
|
|
90
97
|
# #>pdf-composer
|
|
@@ -104,7 +111,7 @@ module HexaPDF
|
|
|
104
111
|
# It is also possible to use row and column spans:
|
|
105
112
|
#
|
|
106
113
|
# #>pdf-composer
|
|
107
|
-
# cells = [[{content: layout.text('A'), col_span: 2}, {content: layout.text(
|
|
114
|
+
# cells = [[{content: layout.text('A'), col_span: 2}, {content: layout.text("B\nB\nB"), row_span: 2}],
|
|
108
115
|
# [{content: layout.text('C'), col_span: 2, row_span: 2}],
|
|
109
116
|
# [layout.text('D')]]
|
|
110
117
|
# composer.table(cells)
|
|
@@ -119,6 +126,15 @@ module HexaPDF
|
|
|
119
126
|
# [layout.text('E'), layout.text('F')]]
|
|
120
127
|
# composer.column(height: 90) {|col| col.table(cells, header: header, footer: footer) }
|
|
121
128
|
#
|
|
129
|
+
# While the width of a cell is determined by the #column_widths array, the height is
|
|
130
|
+
# automatically determined during fitting of the content. However, it is also possible to use a
|
|
131
|
+
# fixed height (only if the actual content is smaller or equal than it):
|
|
132
|
+
#
|
|
133
|
+
# #>pdf-composer
|
|
134
|
+
# cells = [[{content: layout.text('A'), min_height: 5}, layout.text('B')],
|
|
135
|
+
# [{content: layout.text('C'), min_height: 40}, layout.text('D')]]
|
|
136
|
+
# composer.table(cells)
|
|
137
|
+
#
|
|
122
138
|
# The cells can be styled using a callable object for more complex styling:
|
|
123
139
|
#
|
|
124
140
|
# #>pdf-composer
|
|
@@ -184,13 +200,14 @@ module HexaPDF
|
|
|
184
200
|
attr_accessor :children
|
|
185
201
|
|
|
186
202
|
# Creates a new Cell instance.
|
|
187
|
-
def initialize(row:, column:, children: nil, row_span: nil, col_span: nil, **kwargs)
|
|
203
|
+
def initialize(row:, column:, children: nil, min_height: nil, row_span: nil, col_span: nil, **kwargs)
|
|
188
204
|
super(**kwargs, width: 0, height: 0)
|
|
189
205
|
@children = children
|
|
190
206
|
@row = row
|
|
191
207
|
@column = column
|
|
192
208
|
@row_span = row_span || 1
|
|
193
209
|
@col_span = col_span || 1
|
|
210
|
+
@min_height = min_height
|
|
194
211
|
style.border.width.set(1) unless style.border?
|
|
195
212
|
style.border.draw_on_bounds = true
|
|
196
213
|
style.padding.set(5) unless style.padding?
|
|
@@ -250,6 +267,11 @@ module HexaPDF
|
|
|
250
267
|
@fit_results = []
|
|
251
268
|
fit_result.success!
|
|
252
269
|
end
|
|
270
|
+
|
|
271
|
+
if @min_height && @height < @min_height
|
|
272
|
+
@height = @preferred_height = @min_height
|
|
273
|
+
fit_result.failure! if available_height < @height
|
|
274
|
+
end
|
|
253
275
|
end
|
|
254
276
|
|
|
255
277
|
# Draws the content of the cell.
|
|
@@ -291,6 +313,8 @@ module HexaPDF
|
|
|
291
313
|
#
|
|
292
314
|
# +:col_span+:: An integer specifying the number of columsn this cell should span.
|
|
293
315
|
#
|
|
316
|
+
# +:min_height+:: A number specifying the minimum height of the table cell.
|
|
317
|
+
#
|
|
294
318
|
# +:properties+:: A hash of properties (see Box#properties) to be set on the cell itself.
|
|
295
319
|
#
|
|
296
320
|
# All other key-value pairs are taken to be cell styling information (like
|
|
@@ -382,7 +406,14 @@ module HexaPDF
|
|
|
382
406
|
def fit_rows(start_row, available_height, column_info, frame)
|
|
383
407
|
height = available_height
|
|
384
408
|
last_fitted_row_index = -1
|
|
409
|
+
row_heights = {}
|
|
410
|
+
zero_height_rows = {}
|
|
411
|
+
row_spans = []
|
|
412
|
+
|
|
385
413
|
@cells[start_row..-1].each.with_index(start_row) do |columns, row_index|
|
|
414
|
+
# 1. Fit all columns of the row and record the max height of all non-row-span cells. If
|
|
415
|
+
# a row has zero height (usually because it only has row-span cells), record that
|
|
416
|
+
# information. Additionally store all cells with row-spans.
|
|
386
417
|
row_fit = true
|
|
387
418
|
row_height = 0
|
|
388
419
|
columns.each_with_index do |cell, col_index|
|
|
@@ -396,27 +427,67 @@ module HexaPDF
|
|
|
396
427
|
row_fit = false
|
|
397
428
|
break
|
|
398
429
|
end
|
|
399
|
-
cell.
|
|
400
|
-
|
|
401
|
-
|
|
430
|
+
if row_height < cell.preferred_height && cell.row_span == 1
|
|
431
|
+
row_height = cell.preferred_height
|
|
432
|
+
end
|
|
433
|
+
row_spans << cell if cell.row_span > 1
|
|
402
434
|
end
|
|
403
435
|
|
|
404
|
-
if
|
|
405
|
-
seen = {}
|
|
406
|
-
columns.each do |cell|
|
|
407
|
-
next if seen[cell]
|
|
408
|
-
cell.update_height(cell.row == row_index ? row_height : cell.height + row_height)
|
|
409
|
-
seen[cell] = true
|
|
410
|
-
end
|
|
436
|
+
zero_height_rows[row_index] = true if row_height == 0
|
|
411
437
|
|
|
438
|
+
if row_fit
|
|
439
|
+
# 2. If all cells of the row fit, we subtract the recorded row height of the
|
|
440
|
+
# non-row-span cells from the available height for the next pass.
|
|
412
441
|
last_fitted_row_index = row_index
|
|
442
|
+
row_heights[row_index] = row_height
|
|
413
443
|
available_height -= row_height
|
|
444
|
+
|
|
445
|
+
# 3. We look at all row-span cells that end at the current row index. If the row-span
|
|
446
|
+
# cell is larger than the sum of the row heights, we proportionally enlarge the
|
|
447
|
+
# stored height of each spanned row and subtract the difference from the available
|
|
448
|
+
# height for the next pass. If the row span contains initially zero-height rows,
|
|
449
|
+
# only those rows are enlarged. Row-span cells themselves are not updated at this
|
|
450
|
+
# point!
|
|
451
|
+
row_spans.each do |cell|
|
|
452
|
+
upper_row_index = cell.row + cell.row_span - 1
|
|
453
|
+
next unless upper_row_index == row_index
|
|
454
|
+
|
|
455
|
+
rows = cell.row.upto(upper_row_index)
|
|
456
|
+
row_span_height = rows.sum {|ri| row_heights[ri] }
|
|
457
|
+
if row_span_height < cell.preferred_height
|
|
458
|
+
zero_height_rows_in_span = rows.select {|ri| zero_height_rows[ri] }
|
|
459
|
+
rows = zero_height_rows_in_span if zero_height_rows_in_span.size > 0
|
|
460
|
+
adjustment = (cell.preferred_height - row_span_height) / rows.size.to_f
|
|
461
|
+
rows.each {|ri| row_heights[ri] += adjustment }
|
|
462
|
+
available_height -= cell.preferred_height - row_span_height
|
|
463
|
+
end
|
|
464
|
+
end
|
|
414
465
|
else
|
|
415
466
|
last_fitted_row_index = columns.min_by(&:row).row - 1 if height != available_height
|
|
416
467
|
break
|
|
417
468
|
end
|
|
418
469
|
end
|
|
419
470
|
|
|
471
|
+
if last_fitted_row_index >= 0
|
|
472
|
+
# 4. Once all possible rows have been fitted and the heights of the rows are fixed, the
|
|
473
|
+
# final height and top-left corner of each cell needs to be set.
|
|
474
|
+
running_height = 0
|
|
475
|
+
@cells[start_row..last_fitted_row_index].each.with_index(start_row) do |columns, row_index|
|
|
476
|
+
columns.each_with_index do |cell, col_index|
|
|
477
|
+
next if cell.row != row_index || cell.column != col_index
|
|
478
|
+
cell.left = column_info[cell.column].first
|
|
479
|
+
cell.top = running_height
|
|
480
|
+
if cell.row_span == 1
|
|
481
|
+
cell.update_height(row_heights[row_index])
|
|
482
|
+
else
|
|
483
|
+
new_height = cell.row.upto(cell.row + cell.row_span - 1).sum {|ri| row_heights[ri] }
|
|
484
|
+
cell.update_height(new_height)
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
running_height += row_heights[row_index]
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
420
491
|
[height - available_height, last_fitted_row_index < start_row ? -1 : last_fitted_row_index]
|
|
421
492
|
end
|
|
422
493
|
|
|
@@ -459,11 +530,12 @@ module HexaPDF
|
|
|
459
530
|
children = content.delete(:content)
|
|
460
531
|
row_span = content.delete(:row_span)
|
|
461
532
|
col_span = content.delete(:col_span)
|
|
533
|
+
min_height = content.delete(:min_height)
|
|
462
534
|
properties = content.delete(:properties)
|
|
463
535
|
style = content
|
|
464
536
|
end
|
|
465
537
|
cell = Cell.new(children: children, row: row_index, column: col_index,
|
|
466
|
-
row_span: row_span, col_span: col_span)
|
|
538
|
+
row_span: row_span, col_span: col_span, min_height: min_height)
|
|
467
539
|
cell_style_block&.call(cell)
|
|
468
540
|
cell.style.update(**style) if style
|
|
469
541
|
cell.properties.update(properties) if properties
|
|
@@ -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-2025 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-2025 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
|
|
@@ -55,6 +55,10 @@ module HexaPDF
|
|
|
55
55
|
# The rectangle with the bottom-left corner (#x_min, #y_min) and the top-right corner (#x_max,
|
|
56
56
|
# #y_max) describes the minimum bounding box of the whole text fragment and is usually *not*
|
|
57
57
|
# equal to the box (0, 0)-(#width, #height).
|
|
58
|
+
#
|
|
59
|
+
# *Note*: This class should not be used directly but via
|
|
60
|
+
# HexaPDF::Document::Layout#text_fragments. This way the whole document layout infrastructure
|
|
61
|
+
# like font fallback and such is automatically used.
|
|
58
62
|
class TextFragment
|
|
59
63
|
|
|
60
64
|
using NumericRefinements
|
|
@@ -64,6 +68,8 @@ module HexaPDF
|
|
|
64
68
|
# The needed style of the text fragment is specified by the +style+ argument (see
|
|
65
69
|
# Style::create for details). Note that the resulting style object needs at least the font
|
|
66
70
|
# set.
|
|
71
|
+
#
|
|
72
|
+
# For internal use, see the note under TextFragment for details.
|
|
67
73
|
def self.create(text, style)
|
|
68
74
|
style = Style.create(style)
|
|
69
75
|
fragment = new(style.font.decode_utf8(text), style)
|
|
@@ -90,6 +96,8 @@ module HexaPDF
|
|
|
90
96
|
# The needed style of the text fragments is specified by the +style+ argument (see
|
|
91
97
|
# Style::create for details). Note that the resulting style object needs at least the font
|
|
92
98
|
# set.
|
|
99
|
+
#
|
|
100
|
+
# For internal use, see the note under TextFragment for details.
|
|
93
101
|
def self.create_with_fallback_glyphs(text, style)
|
|
94
102
|
return [create(text, style)] if !block_given? || text.empty?
|
|
95
103
|
|
|
@@ -155,6 +163,8 @@ module HexaPDF
|
|
|
155
163
|
#
|
|
156
164
|
# The argument +style+ can either be a Style object or a hash of style properties, see
|
|
157
165
|
# Style::create for details.
|
|
166
|
+
#
|
|
167
|
+
# For internal use, see the note under TextFragment for details.
|
|
158
168
|
def initialize(items, style, properties: nil)
|
|
159
169
|
@items = items
|
|
160
170
|
@style = Style.create(style)
|
|
@@ -235,6 +245,7 @@ module HexaPDF
|
|
|
235
245
|
end
|
|
236
246
|
end
|
|
237
247
|
|
|
248
|
+
in_text_object = (canvas.graphics_object == :text)
|
|
238
249
|
canvas.begin_text
|
|
239
250
|
tlm = canvas.graphics_state.tlm
|
|
240
251
|
tx = x - tlm.e
|
|
@@ -248,7 +259,7 @@ module HexaPDF
|
|
|
248
259
|
elsif ty.abs < PRECISION
|
|
249
260
|
canvas.move_text_cursor(offset: [tx, 0], absolute: false)
|
|
250
261
|
else
|
|
251
|
-
canvas.move_text_cursor(offset: [x, y])
|
|
262
|
+
canvas.move_text_cursor(offset: [x, y], absolute: in_text_object)
|
|
252
263
|
end
|
|
253
264
|
canvas.show_glyphs_only(items)
|
|
254
265
|
|
|
@@ -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-2025 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-2025 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-2025 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.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-2025 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-2025 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-2025 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-2025 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
|
|
@@ -305,8 +305,8 @@ module HexaPDF
|
|
|
305
305
|
result
|
|
306
306
|
rescue HexaPDF::Error
|
|
307
307
|
raise
|
|
308
|
-
rescue StandardError
|
|
309
|
-
yield("
|
|
308
|
+
rescue StandardError => e
|
|
309
|
+
yield("Unexpected error encountered: #{e.message}", false, self) if block_given?
|
|
310
310
|
false
|
|
311
311
|
end
|
|
312
312
|
|
|
@@ -372,7 +372,7 @@ module HexaPDF
|
|
|
372
372
|
|
|
373
373
|
# Computes the hash value based on the object and generation numbers.
|
|
374
374
|
def hash
|
|
375
|
-
oid
|
|
375
|
+
[oid, gen].hash
|
|
376
376
|
end
|
|
377
377
|
|
|
378
378
|
def inspect #:nodoc:
|