hexapdf 0.23.0 → 0.24.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 +66 -0
- data/LICENSE +1 -1
- data/Rakefile +1 -1
- data/examples/016-frame_automatic_box_placement.rb +7 -2
- data/examples/017-frame_text_flow.rb +10 -18
- data/examples/020-column_box.rb +40 -0
- data/examples/021-list_box.rb +26 -0
- data/lib/hexapdf/cli/batch.rb +1 -1
- data/lib/hexapdf/cli/command.rb +1 -1
- data/lib/hexapdf/cli/files.rb +1 -1
- data/lib/hexapdf/cli/fonts.rb +1 -1
- data/lib/hexapdf/cli/form.rb +2 -2
- data/lib/hexapdf/cli/image2pdf.rb +1 -1
- data/lib/hexapdf/cli/images.rb +1 -1
- data/lib/hexapdf/cli/info.rb +2 -2
- data/lib/hexapdf/cli/inspect.rb +2 -2
- 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/cli.rb +1 -1
- data/lib/hexapdf/composer.rb +45 -126
- data/lib/hexapdf/configuration.rb +17 -1
- data/lib/hexapdf/content/canvas.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 +2 -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/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/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 +397 -0
- data/lib/hexapdf/document/pages.rb +17 -1
- data/lib/hexapdf/document/signatures.rb +5 -4
- data/lib/hexapdf/document.rb +8 -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 +30 -21
- 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/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 +1 -1
- 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 +2 -2
- 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 +1 -1
- data/lib/hexapdf/font/true_type.rb +1 -1
- data/lib/hexapdf/font/true_type_wrapper.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.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 +1 -1
- data/lib/hexapdf/font_loader/standard14.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 +1 -1
- data/lib/hexapdf/layout/box.rb +121 -22
- data/lib/hexapdf/layout/box_fitter.rb +136 -0
- data/lib/hexapdf/layout/column_box.rb +247 -0
- data/lib/hexapdf/layout/frame.rb +155 -139
- data/lib/hexapdf/layout/image_box.rb +19 -4
- data/lib/hexapdf/layout/inline_box.rb +1 -1
- data/lib/hexapdf/layout/line.rb +1 -1
- data/lib/hexapdf/layout/list_box.rb +355 -0
- data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
- data/lib/hexapdf/layout/style.rb +5 -1
- data/lib/hexapdf/layout/text_box.rb +20 -9
- data/lib/hexapdf/layout/text_fragment.rb +3 -2
- data/lib/hexapdf/layout/text_layouter.rb +17 -2
- data/lib/hexapdf/layout/text_shaper.rb +1 -1
- data/lib/hexapdf/layout/width_from_polygon.rb +12 -7
- data/lib/hexapdf/layout.rb +4 -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 -8
- 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 +1 -1
- data/lib/hexapdf/stream.rb +1 -1
- data/lib/hexapdf/task/dereference.rb +1 -1
- data/lib/hexapdf/task/optimize.rb +1 -1
- data/lib/hexapdf/task.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/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/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/link.rb +1 -1
- 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 +1 -1
- data/lib/hexapdf/type/annotations.rb +1 -1
- data/lib/hexapdf/type/catalog.rb +1 -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 +1 -1
- 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 +1 -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/names.rb +1 -1
- data/lib/hexapdf/type/object_stream.rb +1 -1
- data/lib/hexapdf/type/page.rb +1 -1
- data/lib/hexapdf/type/page_tree_node.rb +19 -2
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/signature/adbe_pkcs7_detached.rb +1 -1
- data/lib/hexapdf/type/signature/adbe_x509_rsa_sha1.rb +1 -1
- data/lib/hexapdf/type/signature/handler.rb +1 -1
- data/lib/hexapdf/type/signature/verification_result.rb +1 -1
- data/lib/hexapdf/type/signature.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +2 -2
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +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/version.rb +2 -2
- data/lib/hexapdf/writer.rb +9 -7
- data/lib/hexapdf/xref_section.rb +1 -1
- data/lib/hexapdf.rb +1 -1
- data/test/hexapdf/content/graphic_object/test_geom2d.rb +1 -1
- data/test/hexapdf/document/test_destinations.rb +1 -1
- data/test/hexapdf/document/test_images.rb +1 -1
- data/test/hexapdf/document/test_layout.rb +264 -0
- data/test/hexapdf/document/test_pages.rb +9 -0
- data/test/hexapdf/document/test_signatures.rb +10 -3
- data/test/hexapdf/encryption/test_security_handler.rb +1 -1
- data/test/hexapdf/font/encoding/test_glyph_list.rb +4 -0
- data/test/hexapdf/layout/test_box.rb +53 -3
- data/test/hexapdf/layout/test_box_fitter.rb +62 -0
- data/test/hexapdf/layout/test_column_box.rb +159 -0
- data/test/hexapdf/layout/test_frame.rb +99 -38
- data/test/hexapdf/layout/test_image_box.rb +1 -1
- data/test/hexapdf/layout/test_list_box.rb +249 -0
- data/test/hexapdf/layout/test_text_box.rb +17 -2
- data/test/hexapdf/layout/test_text_fragment.rb +1 -1
- data/test/hexapdf/layout/test_text_layouter.rb +42 -17
- data/test/hexapdf/layout/test_width_from_polygon.rb +13 -0
- data/test/hexapdf/test_composer.rb +11 -0
- data/test/hexapdf/test_dictionary_fields.rb +9 -9
- data/test/hexapdf/test_document.rb +4 -4
- data/test/hexapdf/test_filter.rb +1 -1
- data/test/hexapdf/test_parser.rb +0 -2
- data/test/hexapdf/test_revisions.rb +2 -2
- data/test/hexapdf/test_serializer.rb +1 -5
- data/test/hexapdf/test_writer.rb +58 -3
- data/test/hexapdf/type/test_page_tree_node.rb +21 -1
- data/test/hexapdf/type/test_trailer.rb +3 -3
- data/test/test_helper.rb +5 -1
- metadata +28 -3
|
@@ -0,0 +1,355 @@
|
|
|
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-2022 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/layout/box'
|
|
38
|
+
require 'hexapdf/layout/box_fitter'
|
|
39
|
+
require 'hexapdf/layout/text_box'
|
|
40
|
+
require 'hexapdf/layout/text_fragment'
|
|
41
|
+
|
|
42
|
+
module HexaPDF
|
|
43
|
+
module Layout
|
|
44
|
+
|
|
45
|
+
# A ListBox arranges its children as unordered or ordered list items.
|
|
46
|
+
#
|
|
47
|
+
# The indentation of the contents from the left (#content_indentation) as well as the type of
|
|
48
|
+
# item (#item_type) can be specified. Additionally, it is possible to define the start number
|
|
49
|
+
# for ordered lists (#start_number) and the amount of spacing between items (#item_spacing).
|
|
50
|
+
#
|
|
51
|
+
# If the list box has padding and/or borders specified, they are handled like with any other
|
|
52
|
+
# box. This means they are around all items and their contents and are not used separately for
|
|
53
|
+
# each item.
|
|
54
|
+
#
|
|
55
|
+
# The following style properties are used (additionally to those used by the parent class):
|
|
56
|
+
#
|
|
57
|
+
# Style#position::
|
|
58
|
+
# If this is set to :flow, the frames created for the list items will take the shape of the
|
|
59
|
+
# frame into account. This also means that the +available_width+ and +available_height+
|
|
60
|
+
# arguments are ignored.
|
|
61
|
+
class ListBox < Box
|
|
62
|
+
|
|
63
|
+
# The child boxes of this ListBox. They need to be finalized before #fit is called.
|
|
64
|
+
attr_reader :children
|
|
65
|
+
|
|
66
|
+
# The type of list item marker to be rendered before the list item contents.
|
|
67
|
+
#
|
|
68
|
+
# The following values are supported (and :disc is the default):
|
|
69
|
+
#
|
|
70
|
+
# :disc::
|
|
71
|
+
#
|
|
72
|
+
# Draws a filled disc for the items of the unordered list.
|
|
73
|
+
#
|
|
74
|
+
# #>pdf-composer100
|
|
75
|
+
# composer.box(:list, item_type: :disc) do |list|
|
|
76
|
+
# list.lorem_ipsum_box(sentences: 1)
|
|
77
|
+
# end
|
|
78
|
+
#
|
|
79
|
+
# :circle::
|
|
80
|
+
#
|
|
81
|
+
# Draws an unfilled circle for the items of the unordered list.
|
|
82
|
+
#
|
|
83
|
+
# #>pdf-composer100
|
|
84
|
+
# composer.box(:list, item_type: :circle) do |list|
|
|
85
|
+
# list.lorem_ipsum_box(sentences: 1)
|
|
86
|
+
# end
|
|
87
|
+
#
|
|
88
|
+
# :square::
|
|
89
|
+
#
|
|
90
|
+
# Draws a filled square for the items of the unordered list.
|
|
91
|
+
#
|
|
92
|
+
# #>pdf-composer100
|
|
93
|
+
# composer.box(:list, item_type: :square) do |list|
|
|
94
|
+
# list.lorem_ipsum_box(sentences: 1)
|
|
95
|
+
# end
|
|
96
|
+
#
|
|
97
|
+
# :decimal::
|
|
98
|
+
#
|
|
99
|
+
# Draws the numbers in decimal form, starting from #start_number) for the items of
|
|
100
|
+
# the ordered list.
|
|
101
|
+
#
|
|
102
|
+
# #>pdf-composer100
|
|
103
|
+
# composer.box(:list, item_type: :decimal) do |list|
|
|
104
|
+
# 5.times { list.lorem_ipsum_box(sentences: 1) }
|
|
105
|
+
# end
|
|
106
|
+
#
|
|
107
|
+
# custom marker::
|
|
108
|
+
#
|
|
109
|
+
# Additionally, it is possible to specify an object as value that responds to
|
|
110
|
+
# #call(document, box, index) where +document+ is the HexaPDF::Document, +box+ is the list
|
|
111
|
+
# box, and +index+ is the current item index, starting at 0. The return value needs to be a
|
|
112
|
+
# Box object which is then fit into the content indentation area and drawn.
|
|
113
|
+
#
|
|
114
|
+
# #>pdf-composer100
|
|
115
|
+
# image = lambda do |document, box, index|
|
|
116
|
+
# document.layout.image_box(machu_picchu, height: box.style.font_size)
|
|
117
|
+
# end
|
|
118
|
+
# composer.box(:list, item_type: image) do |list|
|
|
119
|
+
# 2.times { list.lorem_ipsum_box(sentences: 1) }
|
|
120
|
+
# end
|
|
121
|
+
attr_reader :item_type
|
|
122
|
+
|
|
123
|
+
# The start number when using an #item_type that represents an ordered list.
|
|
124
|
+
#
|
|
125
|
+
# The default value for this is 1.
|
|
126
|
+
#
|
|
127
|
+
# Example:
|
|
128
|
+
#
|
|
129
|
+
# #>pdf-composer100
|
|
130
|
+
# composer.box(:list, item_type: :decimal, start_number: 3) do |list|
|
|
131
|
+
# 2.times { list.lorem_ipsum_box(sentences: 1) }
|
|
132
|
+
# end
|
|
133
|
+
attr_reader :start_number
|
|
134
|
+
|
|
135
|
+
# The indentation of the list content in PDF points. The item marker will be inside this
|
|
136
|
+
# indentation.
|
|
137
|
+
#
|
|
138
|
+
# The default value is two times the font size.
|
|
139
|
+
#
|
|
140
|
+
# Example:
|
|
141
|
+
#
|
|
142
|
+
# #>pdf-composer100
|
|
143
|
+
# composer.box(:list) {|list| list.lorem_ipsum_box(sentences: 1) }
|
|
144
|
+
# composer.box(:list, content_indentation: 50) do |list|
|
|
145
|
+
# list.lorem_ipsum_box(sentences: 1)
|
|
146
|
+
# end
|
|
147
|
+
attr_reader :content_indentation
|
|
148
|
+
|
|
149
|
+
# The spacing between two consecutive list items.
|
|
150
|
+
#
|
|
151
|
+
# The default value is zero.
|
|
152
|
+
#
|
|
153
|
+
# Example:
|
|
154
|
+
#
|
|
155
|
+
# #>pdf-composer
|
|
156
|
+
# composer.box(:list, item_spacing: 10) do |list|
|
|
157
|
+
# 3.times { list.lorem_ipsum_box(sentences: 1) }
|
|
158
|
+
# end
|
|
159
|
+
attr_reader :item_spacing
|
|
160
|
+
|
|
161
|
+
# Creates a new ListBox object for the given child boxes in +children+.
|
|
162
|
+
def initialize(children: [], item_type: :disc, content_indentation: nil, start_number: 1,
|
|
163
|
+
item_spacing: 0, **kwargs)
|
|
164
|
+
super(**kwargs)
|
|
165
|
+
@children = children
|
|
166
|
+
@item_type = item_type
|
|
167
|
+
@content_indentation = content_indentation || 2 * style.font_size
|
|
168
|
+
@start_number = start_number
|
|
169
|
+
@item_spacing = item_spacing
|
|
170
|
+
|
|
171
|
+
@results = nil
|
|
172
|
+
@results_item_marker_x = nil
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Returns +true+ as the 'position' style property value :flow is supported.
|
|
176
|
+
def supports_position_flow?
|
|
177
|
+
true
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Fits the list box into the available space.
|
|
181
|
+
def fit(available_width, available_height, frame)
|
|
182
|
+
@width = if @initial_width > 0
|
|
183
|
+
@initial_width
|
|
184
|
+
else
|
|
185
|
+
(style.position == :flow ? frame.width : available_width)
|
|
186
|
+
end
|
|
187
|
+
height = if @initial_height > 0
|
|
188
|
+
@initial_height - reserved_height
|
|
189
|
+
else
|
|
190
|
+
(style.position == :flow ? frame.y - frame.bottom : available_height) - reserved_height
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
width = @width - reserved_width
|
|
194
|
+
left = (style.position == :flow ? frame.left : frame.x) + reserved_width_left
|
|
195
|
+
top = frame.y - reserved_height_top
|
|
196
|
+
|
|
197
|
+
# The left side of the frame of an item is always indented, regardless of style.position
|
|
198
|
+
item_frame_left = left + @content_indentation
|
|
199
|
+
item_frame_width = width - @content_indentation
|
|
200
|
+
|
|
201
|
+
# We can remove the content indentation for a rectangle by just modifying left and width
|
|
202
|
+
unless style.position == :flow
|
|
203
|
+
left = item_frame_left
|
|
204
|
+
width = item_frame_width
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
@results = []
|
|
208
|
+
@results_item_marker_x = []
|
|
209
|
+
|
|
210
|
+
@children.each_with_index do |child, index|
|
|
211
|
+
shape = Geom2D::Polygon([left, top - height],
|
|
212
|
+
[left + width, top - height],
|
|
213
|
+
[left + width, top],
|
|
214
|
+
[left, top])
|
|
215
|
+
if style.position == :flow
|
|
216
|
+
shape = Geom2D::Algorithms::PolygonOperation.run(frame.shape, shape, :intersection)
|
|
217
|
+
remove_indent_from_frame_shape(shape) unless shape.polygons.empty?
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
#p [:list, left, width, shape]
|
|
221
|
+
|
|
222
|
+
item_frame = Frame.new(item_frame_left, top - height, item_frame_width, height, shape: shape)
|
|
223
|
+
|
|
224
|
+
#p [index, item_frame.x, @results_item_marker_x]
|
|
225
|
+
@results_item_marker_x << item_frame.x - content_indentation
|
|
226
|
+
|
|
227
|
+
box_fitter = BoxFitter.new([item_frame])
|
|
228
|
+
Array(child).each {|box| box_fitter.fit(box) }
|
|
229
|
+
@results << box_fitter
|
|
230
|
+
|
|
231
|
+
top -= box_fitter.content_heights[0] + item_spacing
|
|
232
|
+
height -= box_fitter.content_heights[0] + item_spacing
|
|
233
|
+
|
|
234
|
+
break if !box_fitter.fit_successful? || height <= 0
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
@height = @results.sum {|box_fitter| box_fitter.content_heights[0] } +
|
|
238
|
+
(@results.count - 1) * item_spacing +
|
|
239
|
+
reserved_height
|
|
240
|
+
|
|
241
|
+
@fit_successful = @results.all?(&:fit_successful?) && @results.size == @children.size
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
private
|
|
245
|
+
|
|
246
|
+
# Removes the +content_indentation+ from the left side of the given shape (a Geom2D::PolygonSet).
|
|
247
|
+
def remove_indent_from_frame_shape(shape)
|
|
248
|
+
polygon_index = 0
|
|
249
|
+
data = []
|
|
250
|
+
|
|
251
|
+
# Determine the lower-left-most and upper-left-most vertices and their indices, together
|
|
252
|
+
# with the polygon index that holds them and the direction wrt to the indices from
|
|
253
|
+
# upper-left-most to lower-left-most.
|
|
254
|
+
shape.polygons.each_with_index do |polygon, pindex|
|
|
255
|
+
lower_vertex = upper_vertex = polygon[0]
|
|
256
|
+
lower_index = upper_index = 0
|
|
257
|
+
1.upto(polygon.nr_of_vertices - 1) do |i|
|
|
258
|
+
v = polygon[i]
|
|
259
|
+
if v.y < lower_vertex.y || (v.y == lower_vertex.y && v.x <= lower_vertex.x)
|
|
260
|
+
lower_vertex = v
|
|
261
|
+
lower_index = i
|
|
262
|
+
elsif v.y > upper_vertex.y || (v.y == upper_vertex.y && v.x <= upper_vertex.x)
|
|
263
|
+
upper_vertex = v
|
|
264
|
+
upper_index = i
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
direction = upper_vertex.x == polygon[(upper_index + 1) % polygon.nr_of_vertices].x ? 1 : -1
|
|
268
|
+
if data.empty? || data[0].x > lower_vertex.x
|
|
269
|
+
polygon_index = pindex
|
|
270
|
+
data = [lower_vertex, lower_index, upper_vertex, upper_index, direction]
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Now we have all the data to remove the indentation on the left side of the polygon. This
|
|
275
|
+
# is done by shifting all vertices between and including the lower-left-most and
|
|
276
|
+
# upper-left-most vertices to the right.
|
|
277
|
+
vertices = shape.polygons[polygon_index].to_a
|
|
278
|
+
point = data[2]
|
|
279
|
+
index = data[3]
|
|
280
|
+
while point != data[0]
|
|
281
|
+
vertices[index] = Geom2D::Point(point.x + content_indentation, point.y)
|
|
282
|
+
index = (index + data[4]) % vertices.size
|
|
283
|
+
point = vertices[index]
|
|
284
|
+
end
|
|
285
|
+
vertices[data[1]] = Geom2D::Point(data[0].x + content_indentation, data[0].y)
|
|
286
|
+
|
|
287
|
+
shape.polygons[polygon_index] = Geom2D::Polygon(*vertices)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Splits the content of the list box. This method is called from Box#split.
|
|
291
|
+
def split_content(_available_width, _available_height, _frame)
|
|
292
|
+
remaining_boxes = @results[-1].remaining_boxes
|
|
293
|
+
first_is_split_box = remaining_boxes.first&.split_box?
|
|
294
|
+
children = (remaining_boxes.empty? ? [] : [remaining_boxes]) + @children[@results.size..-1]
|
|
295
|
+
|
|
296
|
+
box = create_split_box(split_box_value: first_is_split_box ? :hide_first_marker : :show_first_marker)
|
|
297
|
+
box.instance_variable_set(:@children, children)
|
|
298
|
+
box.instance_variable_set(:@start_number,
|
|
299
|
+
@start_number + @results.size + (first_is_split_box ? -1 : 0))
|
|
300
|
+
box.instance_variable_set(:@results, [])
|
|
301
|
+
box.instance_variable_set(:@results_item_marker_x, [])
|
|
302
|
+
|
|
303
|
+
[self, box]
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# Creates a box for the item marker at the given item index, using #item_style to decide on
|
|
307
|
+
# its contents.
|
|
308
|
+
def item_marker_box(document, index)
|
|
309
|
+
return @item_type.call(document, self, index) if @item_type.kind_of?(Proc)
|
|
310
|
+
return @item_marker_box if defined?(@item_marker_box)
|
|
311
|
+
|
|
312
|
+
fragment = case @item_type
|
|
313
|
+
when :disc
|
|
314
|
+
TextFragment.create("•", font: document.fonts.add("Times"),
|
|
315
|
+
font_size: style.font_size)
|
|
316
|
+
when :circle
|
|
317
|
+
TextFragment.create("❍", font: document.fonts.add("ZapfDingbats"),
|
|
318
|
+
font_size: style.font_size / 2.0,
|
|
319
|
+
text_rise: -style.font_size / 1.8)
|
|
320
|
+
when :square
|
|
321
|
+
TextFragment.create("■", font: document.fonts.add("ZapfDingbats"),
|
|
322
|
+
font_size: style.font_size / 2.0,
|
|
323
|
+
text_rise: -style.font_size / 1.8)
|
|
324
|
+
when :decimal
|
|
325
|
+
text = (@start_number + index).to_s << "."
|
|
326
|
+
decimal_style = {
|
|
327
|
+
font: (style.font? ? style.font : document.fonts.add("Times")),
|
|
328
|
+
font_size: style.font_size || 10,
|
|
329
|
+
}
|
|
330
|
+
TextFragment.create(text, decimal_style)
|
|
331
|
+
else
|
|
332
|
+
raise HexaPDF::Error, "Unknown list item type #{@item_type.inspect}"
|
|
333
|
+
end
|
|
334
|
+
box = TextBox.new(items: [fragment], style: {align: :right, padding: [0, 5, 0, 0]})
|
|
335
|
+
@item_marker_box = box unless @item_type == :decimal
|
|
336
|
+
box
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Draws the list items onto the canvas at position [x, y].
|
|
340
|
+
def draw_content(canvas, _x, _y)
|
|
341
|
+
@results.each_with_index do |box_fitter, index|
|
|
342
|
+
if index != 0 || !split_box? || @split_box == :show_first_marker
|
|
343
|
+
box = item_marker_box(canvas.context.document, index)
|
|
344
|
+
box.fit(content_indentation, box_fitter.content_heights[0], nil)
|
|
345
|
+
box.draw(canvas, @results_item_marker_x[index],
|
|
346
|
+
box_fitter.frames[0].bottom + box_fitter.frames[0].height - box.height)
|
|
347
|
+
end
|
|
348
|
+
box_fitter.fit_results.each {|result| result.draw(canvas) }
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
end
|
|
355
|
+
end
|
|
@@ -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-2022 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-2022 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
|
|
@@ -1145,6 +1145,10 @@ module HexaPDF
|
|
|
1145
1145
|
#
|
|
1146
1146
|
# :flow:: Flows the content of the box inside the frame around objects.
|
|
1147
1147
|
#
|
|
1148
|
+
# A box needs to indicate whether it supports this value by implementing the
|
|
1149
|
+
# #supports_position_flow? method and returning +true+ if it does or +false+ if it
|
|
1150
|
+
# doesn't.
|
|
1151
|
+
#
|
|
1148
1152
|
# :absolute:: Position the box at an absolute position relative to the frame. The coordinates
|
|
1149
1153
|
# are given via the position hint.
|
|
1150
1154
|
#
|
|
@@ -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-2022 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
|
|
@@ -47,18 +47,23 @@ module HexaPDF
|
|
|
47
47
|
|
|
48
48
|
# Creates a new TextBox object with the given inline items (e.g. TextFragment and InlineBox
|
|
49
49
|
# objects).
|
|
50
|
-
def initialize(items
|
|
50
|
+
def initialize(items:, **kwargs)
|
|
51
51
|
super(**kwargs)
|
|
52
52
|
@tl = TextLayouter.new(style)
|
|
53
53
|
@items = items
|
|
54
54
|
@result = nil
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
# Returns +true+ as the 'position' style property value :flow is supported.
|
|
58
|
+
def supports_position_flow?
|
|
59
|
+
true
|
|
60
|
+
end
|
|
61
|
+
|
|
57
62
|
# Fits the text box into the Frame.
|
|
58
63
|
#
|
|
59
64
|
# Depending on the 'position' style property, the text is either fit into the rectangular area
|
|
60
65
|
# given by +available_width+ and +available_height+, or fit to the outline of the frame
|
|
61
|
-
# starting from the top.
|
|
66
|
+
# starting from the top (when 'position' is set to :flow).
|
|
62
67
|
#
|
|
63
68
|
# The spacing after the last line can be controlled via the style property +last_line_gap+.
|
|
64
69
|
#
|
|
@@ -69,7 +74,7 @@ module HexaPDF
|
|
|
69
74
|
|
|
70
75
|
@width = @height = 0
|
|
71
76
|
@result = if style.position == :flow
|
|
72
|
-
@tl.fit(@items, frame.width_specification, frame.
|
|
77
|
+
@tl.fit(@items, frame.width_specification, frame.shape.bbox.height)
|
|
73
78
|
else
|
|
74
79
|
@width = reserved_width
|
|
75
80
|
@height = reserved_height
|
|
@@ -97,17 +102,15 @@ module HexaPDF
|
|
|
97
102
|
# Splits the text box into two boxes if necessary and possible.
|
|
98
103
|
def split(available_width, available_height, frame)
|
|
99
104
|
fit(available_width, available_height, frame) unless @result
|
|
100
|
-
|
|
105
|
+
|
|
106
|
+
if style.position != :flow && (@width > available_width || @height > available_height)
|
|
101
107
|
[nil, self]
|
|
102
108
|
elsif @result.remaining_items.empty?
|
|
103
109
|
[self]
|
|
104
110
|
elsif @result.lines.empty?
|
|
105
111
|
[nil, self]
|
|
106
112
|
else
|
|
107
|
-
|
|
108
|
-
box.instance_variable_set(:@result, nil)
|
|
109
|
-
box.instance_variable_set(:@items, @result.remaining_items)
|
|
110
|
-
[self, box]
|
|
113
|
+
[self, create_box_for_remaining_items]
|
|
111
114
|
end
|
|
112
115
|
end
|
|
113
116
|
|
|
@@ -124,6 +127,14 @@ module HexaPDF
|
|
|
124
127
|
@result.draw(canvas, x, y + content_height)
|
|
125
128
|
end
|
|
126
129
|
|
|
130
|
+
# Creates a new TextBox instance for the items remaining after fitting the box.
|
|
131
|
+
def create_box_for_remaining_items
|
|
132
|
+
box = create_split_box
|
|
133
|
+
box.instance_variable_set(:@result, nil)
|
|
134
|
+
box.instance_variable_set(:@items, @result.remaining_items)
|
|
135
|
+
box
|
|
136
|
+
end
|
|
137
|
+
|
|
127
138
|
end
|
|
128
139
|
|
|
129
140
|
end
|
|
@@ -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-2022 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
|
|
@@ -273,7 +273,8 @@ module HexaPDF
|
|
|
273
273
|
|
|
274
274
|
# :nodoc:
|
|
275
275
|
def inspect
|
|
276
|
-
"#<#{self.class.name} #{items.inspect}
|
|
276
|
+
"#<#{self.class.name} #{items.reject {|i| i.kind_of?(Numeric) }.map(&:str).join.inspect} " \
|
|
277
|
+
"#{items.inspect}>"
|
|
277
278
|
end
|
|
278
279
|
|
|
279
280
|
private
|
|
@@ -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-2022 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
|
|
@@ -100,6 +100,10 @@ module HexaPDF
|
|
|
100
100
|
:box
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
def inspect #:nodoc:
|
|
104
|
+
"Box[#{@item.inspect}]"
|
|
105
|
+
end
|
|
106
|
+
|
|
103
107
|
end
|
|
104
108
|
|
|
105
109
|
# Used for layouting. Describes a glue item, i.e. an item describing white space that could
|
|
@@ -132,6 +136,10 @@ module HexaPDF
|
|
|
132
136
|
:glue
|
|
133
137
|
end
|
|
134
138
|
|
|
139
|
+
def inspect #:nodoc:
|
|
140
|
+
"Glue[#{@item.inspect}]"
|
|
141
|
+
end
|
|
142
|
+
|
|
135
143
|
end
|
|
136
144
|
|
|
137
145
|
# Used for layouting. Describes a penalty item, i.e. a point where a break is allowed.
|
|
@@ -173,6 +181,10 @@ module HexaPDF
|
|
|
173
181
|
:penalty
|
|
174
182
|
end
|
|
175
183
|
|
|
184
|
+
def inspect #:nodoc:
|
|
185
|
+
"Penalty[#{penalty} #{width} #{@item.inspect}]"
|
|
186
|
+
end
|
|
187
|
+
|
|
176
188
|
# Singleton object describing a Penalty for a prohibited break.
|
|
177
189
|
ProhibitedBreak = new(Penalty::INFINITY)
|
|
178
190
|
|
|
@@ -759,6 +771,9 @@ module HexaPDF
|
|
|
759
771
|
|
|
760
772
|
# item didn't fit into first part, find next available part
|
|
761
773
|
if line.items.empty? && line_fragments.empty?
|
|
774
|
+
# item didn't fit because no more height is available
|
|
775
|
+
next nil if actual_height + item.height > height
|
|
776
|
+
|
|
762
777
|
old_height = actual_height
|
|
763
778
|
while item.width > width_block.call(item.item) && actual_height <= height
|
|
764
779
|
width_spec_index += 1
|
|
@@ -815,7 +830,7 @@ module HexaPDF
|
|
|
815
830
|
if too_wide_box && (too_wide_box.item.kind_of?(TextFragment) &&
|
|
816
831
|
too_wide_box.item.items.size > 1)
|
|
817
832
|
rest[0..rest.index(too_wide_box)] = too_wide_box.item.items.map do |item|
|
|
818
|
-
Box.new(TextFragment.new([item], too_wide_box.item.style))
|
|
833
|
+
Box.new(TextFragment.new([item].freeze, too_wide_box.item.style))
|
|
819
834
|
end
|
|
820
835
|
too_wide_box = nil
|
|
821
836
|
else
|
|
@@ -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-2022 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-2022 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
|
|
@@ -34,12 +34,16 @@
|
|
|
34
34
|
# commercial licenses are available at <https://gettalong.at/hexapdf/>.
|
|
35
35
|
#++
|
|
36
36
|
|
|
37
|
+
require 'geom2d/utils'
|
|
38
|
+
|
|
37
39
|
module HexaPDF
|
|
38
40
|
module Layout
|
|
39
41
|
|
|
40
42
|
# Utility class for generating width specifications for TextLayouter#fit from polygons.
|
|
41
43
|
class WidthFromPolygon
|
|
42
44
|
|
|
45
|
+
include Geom2D::Utils
|
|
46
|
+
|
|
43
47
|
# Creates a new object for the given polygon (or polygon set) and immediately prepares it so
|
|
44
48
|
# that #call can be used.
|
|
45
49
|
#
|
|
@@ -94,14 +98,15 @@ module HexaPDF
|
|
|
94
98
|
|
|
95
99
|
@polygon_segments.each do |segments|
|
|
96
100
|
temp_result = []
|
|
97
|
-
status = if segments.first[0].start_point.y
|
|
101
|
+
status = if float_compare(segments.first[0].start_point.y, y2) >= 0 ||
|
|
102
|
+
float_compare(segments.first[0].start_point.y, y1) <= 0
|
|
98
103
|
:outside
|
|
99
104
|
else
|
|
100
105
|
:inside
|
|
101
106
|
end
|
|
102
107
|
|
|
103
108
|
segments.each do |_segment, miny, maxy, minyx, maxyx, vertical, slope, intercept|
|
|
104
|
-
next unless miny <
|
|
109
|
+
next unless float_compare(miny, y2) < 0 && float_compare(maxy, y1) > 0
|
|
105
110
|
|
|
106
111
|
if vertical
|
|
107
112
|
min_x = max_x = minyx
|
|
@@ -111,9 +116,9 @@ module HexaPDF
|
|
|
111
116
|
min_x, max_x = max_x, min_x if min_x > max_x
|
|
112
117
|
end
|
|
113
118
|
|
|
114
|
-
if miny <=
|
|
119
|
+
if float_compare(miny, y1) <= 0 && float_compare(maxy, y2) >= 0 # segment crosses both lines
|
|
115
120
|
temp_result << [min_x, max_x, :crossed_both]
|
|
116
|
-
elsif miny <=
|
|
121
|
+
elsif float_compare(miny, y1) <= 0 # segment crosses bottom line
|
|
117
122
|
if status == :outside
|
|
118
123
|
temp_result << [min_x, max_x, :crossed_bottom]
|
|
119
124
|
status = :inside
|
|
@@ -127,7 +132,7 @@ module HexaPDF
|
|
|
127
132
|
temp_result << [min_x, max_x, :crossed_bottom]
|
|
128
133
|
status = :outside
|
|
129
134
|
end
|
|
130
|
-
elsif maxy >=
|
|
135
|
+
elsif float_compare(maxy, y2) >= 0 # segment crosses top line
|
|
131
136
|
if status == :outside
|
|
132
137
|
temp_result << [min_x, max_x, :crossed_top]
|
|
133
138
|
status = :inside
|
|
@@ -199,7 +204,7 @@ module HexaPDF
|
|
|
199
204
|
# Prepare the segments and other data for later use.
|
|
200
205
|
def prepare(offset)
|
|
201
206
|
@max_y = @polygon.bbox.max_y - offset
|
|
202
|
-
@polygon_segments = if @polygon.
|
|
207
|
+
@polygon_segments = if @polygon.respond_to?(:polygons)
|
|
203
208
|
@polygon.polygons.map {|polygon| process_polygon(polygon) }
|
|
204
209
|
else
|
|
205
210
|
[process_polygon(@polygon)]
|
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-2022 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
|
|
@@ -50,9 +50,12 @@ module HexaPDF
|
|
|
50
50
|
autoload(:TextLayouter, 'hexapdf/layout/text_layouter')
|
|
51
51
|
autoload(:Box, 'hexapdf/layout/box')
|
|
52
52
|
autoload(:Frame, 'hexapdf/layout/frame')
|
|
53
|
+
autoload(:BoxFitter, 'hexapdf/layout/box_fitter')
|
|
53
54
|
autoload(:WidthFromPolygon, 'hexapdf/layout/width_from_polygon')
|
|
54
55
|
autoload(:TextBox, 'hexapdf/layout/text_box')
|
|
55
56
|
autoload(:ImageBox, 'hexapdf/layout/image_box')
|
|
57
|
+
autoload(:ColumnBox, 'hexapdf/layout/column_box')
|
|
58
|
+
autoload(:ListBox, 'hexapdf/layout/list_box')
|
|
56
59
|
|
|
57
60
|
end
|
|
58
61
|
|
|
@@ -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-2022 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-2022 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-2022 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
|