hexapdf 0.21.1 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +137 -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 +20 -37
- 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 +31 -4
- 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 +19 -6
- data/lib/hexapdf/cli/merge.rb +1 -1
- data/lib/hexapdf/cli/modify.rb +24 -4
- 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 +66 -125
- 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 +2 -2
- data/lib/hexapdf/document/destinations.rb +396 -0
- 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 +46 -90
- 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 +168 -89
- data/lib/hexapdf/layout/frame.rb +155 -140
- 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 +285 -8
- data/lib/hexapdf/layout/text_box.rb +30 -11
- data/lib/hexapdf/layout/text_fragment.rb +3 -2
- data/lib/hexapdf/layout/text_layouter.rb +23 -3
- 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 +9 -2
- data/lib/hexapdf/revisions.rb +152 -51
- 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 +22 -12
- 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 +12 -6
- data/lib/hexapdf/type/acro_form/signature_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/text_field.rb +9 -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 +10 -2
- 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 +48 -4
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/names.rb +14 -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 +3 -2
- 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 +4 -2
- data/lib/hexapdf/version.rb +2 -2
- data/lib/hexapdf/writer.rb +23 -8
- 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 +338 -0
- 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 +3 -3
- 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 +114 -39
- 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 +33 -2
- data/test/hexapdf/layout/test_text_fragment.rb +1 -1
- data/test/hexapdf/layout/test_text_layouter.rb +49 -17
- data/test/hexapdf/layout/test_width_from_polygon.rb +13 -0
- data/test/hexapdf/task/test_optimize.rb +17 -4
- data/test/hexapdf/test_composer.rb +35 -1
- data/test/hexapdf/test_dictionary_fields.rb +10 -10
- data/test/hexapdf/test_document.rb +33 -136
- data/test/hexapdf/test_filter.rb +1 -1
- data/test/hexapdf/test_parser.rb +1 -3
- data/test/hexapdf/test_revision.rb +14 -0
- data/test/hexapdf/test_revisions.rb +137 -29
- data/test/hexapdf/test_serializer.rb +1 -5
- data/test/hexapdf/test_writer.rb +99 -15
- data/test/hexapdf/type/acro_form/test_form.rb +2 -1
- data/test/hexapdf/type/acro_form/test_text_field.rb +17 -0
- data/test/hexapdf/type/test_catalog.rb +8 -0
- data/test/hexapdf/type/test_image.rb +45 -9
- data/test/hexapdf/type/test_names.rb +20 -0
- data/test/hexapdf/type/test_page_tree_node.rb +21 -1
- data/test/hexapdf/type/test_trailer.rb +3 -3
- data/test/hexapdf/type/test_xref_stream.rb +2 -1
- data/test/hexapdf/utils/test_sorted_tree_node.rb +11 -1
- data/test/test_helper.rb +5 -1
- metadata +29 -3
@@ -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
|
@@ -825,7 +840,12 @@ module HexaPDF
|
|
825
840
|
end
|
826
841
|
|
827
842
|
unless lines.empty?
|
828
|
-
|
843
|
+
# Apply baseline offset only for non-variable width text
|
844
|
+
lines.first.y_offset += if width_block.arity == 1
|
845
|
+
lines.first.y_max
|
846
|
+
else
|
847
|
+
initial_baseline_offset(lines, height, actual_height)
|
848
|
+
end
|
829
849
|
end
|
830
850
|
|
831
851
|
Result.new(status, lines, rest)
|
@@ -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
|
data/lib/hexapdf/parser.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# This file is part of HexaPDF.
|
5
5
|
#
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
-
# Copyright (C) 2014-
|
7
|
+
# Copyright (C) 2014-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
|
@@ -62,15 +62,9 @@ module HexaPDF
|
|
62
62
|
@object_stream_data = {}
|
63
63
|
@reconstructed_revision = nil
|
64
64
|
@in_reconstruct_revision = false
|
65
|
-
@contains_xref_streams = false
|
66
65
|
retrieve_pdf_header_offset_and_version
|
67
66
|
end
|
68
67
|
|
69
|
-
# Returns +true+ if the PDF file contains cross-reference streams.
|
70
|
-
def contains_xref_streams?
|
71
|
-
@contains_xref_streams
|
72
|
-
end
|
73
|
-
|
74
68
|
# Returns +true+ if the PDF file was damaged and could be reconstructed.
|
75
69
|
def reconstructed?
|
76
70
|
!@reconstructed_revision.nil?
|
@@ -241,7 +235,6 @@ module HexaPDF
|
|
241
235
|
maybe_raise("Cross-reference stream doesn't contain entry for itself", pos: pos)
|
242
236
|
xref_section.add_in_use_entry(obj.oid, obj.gen, pos)
|
243
237
|
end
|
244
|
-
@contains_xref_streams = true
|
245
238
|
end
|
246
239
|
xref_section.delete(0)
|
247
240
|
[xref_section, trailer]
|
data/lib/hexapdf/pdf_array.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# This file is part of HexaPDF.
|
5
5
|
#
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
-
# Copyright (C) 2014-
|
7
|
+
# Copyright (C) 2014-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/rectangle.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# This file is part of HexaPDF.
|
5
5
|
#
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
-
# Copyright (C) 2014-
|
7
|
+
# Copyright (C) 2014-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/reference.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# This file is part of HexaPDF.
|
5
5
|
#
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
-
# Copyright (C) 2014-
|
7
|
+
# Copyright (C) 2014-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/revision.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# This file is part of HexaPDF.
|
5
5
|
#
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
-
# Copyright (C) 2014-
|
7
|
+
# Copyright (C) 2014-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
|
@@ -82,6 +82,7 @@ module HexaPDF
|
|
82
82
|
@loader = xref_section && (block || loader)
|
83
83
|
@xref_section = xref_section || XRefSection.new
|
84
84
|
@objects = HexaPDF::Utils::ObjectHash.new
|
85
|
+
@all_objects_loaded = false
|
85
86
|
end
|
86
87
|
|
87
88
|
# Returns the next free object number for adding an object to this revision.
|
@@ -209,7 +210,7 @@ module HexaPDF
|
|
209
210
|
def each(only_loaded: false)
|
210
211
|
return to_enum(__method__, only_loaded: only_loaded) unless block_given?
|
211
212
|
|
212
|
-
if
|
213
|
+
if @all_objects_loaded || only_loaded
|
213
214
|
@objects.each {|_oid, _gen, data| yield(data) }
|
214
215
|
else
|
215
216
|
seen = {}
|
@@ -256,6 +257,12 @@ module HexaPDF
|
|
256
257
|
self
|
257
258
|
end
|
258
259
|
|
260
|
+
# Resets the revision by deleting all loaded and added objects from it.
|
261
|
+
def reset_objects
|
262
|
+
@objects = HexaPDF::Utils::ObjectHash.new
|
263
|
+
@all_objects_loaded = false
|
264
|
+
end
|
265
|
+
|
259
266
|
private
|
260
267
|
|
261
268
|
# Loads a single object from the associated cross-reference section.
|
data/lib/hexapdf/revisions.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# This file is part of HexaPDF.
|
5
5
|
#
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
-
# Copyright (C) 2014-
|
7
|
+
# Copyright (C) 2014-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
|
@@ -51,6 +51,10 @@ module HexaPDF
|
|
51
51
|
# the newest revision the highest index. This is also the order in which the revisions get
|
52
52
|
# written.
|
53
53
|
#
|
54
|
+
# *Important*: It is possible to manipulate the individual revisions and their objects oneself but
|
55
|
+
# this should only be done if one is familiar with the inner workings of HexaPDF. Otherwise it is
|
56
|
+
# best to use the convenience methods of this class to create, access or delete indirect objects.
|
57
|
+
#
|
54
58
|
# See: PDF1.7 s7.5.6, HexaPDF::Revision
|
55
59
|
class Revisions
|
56
60
|
|
@@ -68,27 +72,26 @@ module HexaPDF
|
|
68
72
|
|
69
73
|
revisions = []
|
70
74
|
begin
|
71
|
-
|
72
|
-
|
73
|
-
xref_section: xref_section, loader: object_loader)
|
74
|
-
seen_xref_offsets = {parser.startxref_offset => true}
|
75
|
+
offset = parser.startxref_offset
|
76
|
+
seen_xref_offsets = {}
|
75
77
|
|
76
|
-
while
|
77
|
-
!seen_xref_offsets.key?(prev)
|
78
|
+
while offset && !seen_xref_offsets.key?(offset)
|
78
79
|
# PDF1.7 s7.5.5 states that :Prev needs to be indirect, Adobe's reference 3.4.4 says it
|
79
80
|
# should be direct. Adobe's POV is followed here. Same with :XRefStm.
|
80
|
-
xref_section, trailer = parser.load_revision(
|
81
|
-
seen_xref_offsets[
|
81
|
+
xref_section, trailer = parser.load_revision(offset)
|
82
|
+
seen_xref_offsets[offset] = true
|
82
83
|
|
83
|
-
stm =
|
84
|
+
stm = trailer[:XRefStm]
|
84
85
|
if stm && !seen_xref_offsets.key?(stm)
|
85
86
|
stm_xref_section, = parser.load_revision(stm)
|
86
|
-
|
87
|
+
stm_xref_section.merge!(xref_section)
|
88
|
+
xref_section = stm_xref_section
|
87
89
|
seen_xref_offsets[stm] = true
|
88
90
|
end
|
89
91
|
|
90
92
|
revisions.unshift(Revision.new(document.wrap(trailer, type: :XXTrailer),
|
91
93
|
xref_section: xref_section, loader: object_loader))
|
94
|
+
offset = trailer[:Prev]
|
92
95
|
end
|
93
96
|
rescue HexaPDF::MalformedPDFError
|
94
97
|
reconstructed_revision = parser.reconstructed_revision
|
@@ -133,23 +136,154 @@ module HexaPDF
|
|
133
136
|
end
|
134
137
|
end
|
135
138
|
|
136
|
-
# Returns the
|
137
|
-
def
|
138
|
-
@revisions
|
139
|
+
# Returns the next object identifier that should be used when adding a new object.
|
140
|
+
def next_oid
|
141
|
+
@revisions.map(&:next_free_oid).max
|
142
|
+
end
|
143
|
+
|
144
|
+
# :call-seq:
|
145
|
+
# revisions.object(ref) -> obj or nil
|
146
|
+
# revisions.object(oid) -> obj or nil
|
147
|
+
#
|
148
|
+
# Returns the current version of the indirect object for the given exact reference or for the
|
149
|
+
# given object number.
|
150
|
+
#
|
151
|
+
# For references to unknown objects, +nil+ is returned but free objects are represented by a
|
152
|
+
# PDF Null object, not by +nil+!
|
153
|
+
#
|
154
|
+
# See: PDF1.7 s7.3.9
|
155
|
+
def object(ref)
|
156
|
+
i = @revisions.size - 1
|
157
|
+
while i >= 0
|
158
|
+
if (result = @revisions[i].object(ref))
|
159
|
+
return result
|
160
|
+
end
|
161
|
+
i -= 1
|
162
|
+
end
|
163
|
+
nil
|
164
|
+
end
|
165
|
+
|
166
|
+
# :call-seq:
|
167
|
+
# revisions.object?(ref) -> true or false
|
168
|
+
# revisions.object?(oid) -> true or false
|
169
|
+
#
|
170
|
+
# Returns +true+ if one of the revisions contains an indirect object for the given exact
|
171
|
+
# reference or for the given object number.
|
172
|
+
#
|
173
|
+
# Even though this method might return +true+ for some references, #object may return +nil+
|
174
|
+
# because this method takes *all* revisions into account.
|
175
|
+
def object?(ref)
|
176
|
+
@revisions.any? {|rev| rev.object?(ref) }
|
177
|
+
end
|
178
|
+
|
179
|
+
# :call-seq:
|
180
|
+
# revisions.add_object(object) -> object
|
181
|
+
#
|
182
|
+
# Adds the given HexaPDF::Object to the current revision and returns it.
|
183
|
+
#
|
184
|
+
# If +object+ is a direct object, an object number is automatically assigned.
|
185
|
+
def add_object(obj)
|
186
|
+
if obj.indirect? && (rev_obj = current.object(obj.oid))
|
187
|
+
if rev_obj.data == obj.data
|
188
|
+
return obj
|
189
|
+
else
|
190
|
+
raise HexaPDF::Error, "Can't add object because there is already " \
|
191
|
+
"an object with object number #{obj.oid}"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
obj.oid = next_oid unless obj.indirect?
|
196
|
+
current.add(obj)
|
197
|
+
end
|
198
|
+
|
199
|
+
# :call-seq:
|
200
|
+
# revisions.delete_object(ref)
|
201
|
+
# revisions.delete_object(oid)
|
202
|
+
#
|
203
|
+
# Deletes the indirect object specified by an exact reference or by an object number.
|
204
|
+
def delete_object(ref)
|
205
|
+
@revisions.reverse_each do |rev|
|
206
|
+
if rev.object?(ref)
|
207
|
+
rev.delete(ref)
|
208
|
+
break
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# :call-seq:
|
214
|
+
# revisions.each_object(only_current: true, only_loaded: false) {|obj| block } -> revisions
|
215
|
+
# revisions.each_object(only_current: true, only_loaded: false) {|obj, rev| block } -> revisions
|
216
|
+
# revisions.each_object(only_current: true, only_loaded: false) -> Enumerator
|
217
|
+
#
|
218
|
+
# Yields every object and optionally the revision it is in.
|
219
|
+
#
|
220
|
+
# If +only_loaded+ is +true+, only the already loaded objects of the PDF document are yielded.
|
221
|
+
# This does only matter when the document instance was created from an existing PDF document.
|
222
|
+
#
|
223
|
+
# By default, only the current version of each object is returned which implies that each object
|
224
|
+
# number is yielded exactly once. If the +only_current+ option is +false+, all stored objects
|
225
|
+
# from newest to oldest are returned, not only the current version of each object.
|
226
|
+
#
|
227
|
+
# The +only_current+ option can make a difference because the document can contain multiple
|
228
|
+
# revisions:
|
229
|
+
#
|
230
|
+
# * Multiple revisions may contain objects with the same object and generation numbers, e.g.
|
231
|
+
# two (different) objects with oid/gen [3,0].
|
232
|
+
#
|
233
|
+
# * Additionally, there may also be objects with the same object number but different
|
234
|
+
# generation numbers in different revisions, e.g. one object with oid/gen [3,0] and one with
|
235
|
+
# oid/gen [3,1].
|
236
|
+
def each_object(only_current: true, only_loaded: false, &block)
|
237
|
+
unless block_given?
|
238
|
+
return to_enum(__method__, only_current: only_current, only_loaded: only_loaded)
|
239
|
+
end
|
240
|
+
|
241
|
+
yield_rev = (block.arity == 2)
|
242
|
+
oids = {}
|
243
|
+
@revisions.reverse_each do |rev|
|
244
|
+
rev.each(only_loaded: only_loaded) do |obj|
|
245
|
+
next if only_current && oids.include?(obj.oid)
|
246
|
+
yield_rev ? yield(obj, rev) : yield(obj)
|
247
|
+
oids[obj.oid] = true
|
248
|
+
end
|
249
|
+
end
|
250
|
+
self
|
139
251
|
end
|
140
|
-
alias [] revision
|
141
252
|
|
142
253
|
# Returns the current revision.
|
254
|
+
#
|
255
|
+
# *Note*: This method should only be used if one is familiar with the inner workings of HexaPDF
|
256
|
+
# *and the PDF specification.
|
143
257
|
def current
|
144
258
|
@revisions.last
|
145
259
|
end
|
146
260
|
|
147
|
-
# Returns
|
148
|
-
|
149
|
-
|
261
|
+
# Returns a list of all revisions.
|
262
|
+
#
|
263
|
+
# *Note*: This method should only be used if one is familiar with the inner workings of HexaPDF
|
264
|
+
# *and the PDF specification.
|
265
|
+
def all
|
266
|
+
@revisions
|
267
|
+
end
|
268
|
+
|
269
|
+
# :call-seq:
|
270
|
+
# revisions.each {|rev| block } -> revisions
|
271
|
+
# revisions.each -> Enumerator
|
272
|
+
#
|
273
|
+
# Iterates over all revisions from oldest to current one.
|
274
|
+
#
|
275
|
+
# *Note*: This method should only be used if one is familiar with the inner workings of HexaPDF
|
276
|
+
# *and the PDF specification.
|
277
|
+
def each(&block)
|
278
|
+
return to_enum(__method__) unless block_given?
|
279
|
+
@revisions.each(&block)
|
280
|
+
self
|
150
281
|
end
|
151
282
|
|
152
283
|
# Adds a new empty revision to the document and returns it.
|
284
|
+
#
|
285
|
+
# *Note*: This method should only be used if one is familiar with the inner workings of HexaPDF
|
286
|
+
# *and the PDF specification.
|
153
287
|
def add
|
154
288
|
if @revisions.empty?
|
155
289
|
trailer = {}
|
@@ -164,28 +298,6 @@ module HexaPDF
|
|
164
298
|
rev
|
165
299
|
end
|
166
300
|
|
167
|
-
# :call-seq:
|
168
|
-
# revisions.delete(index) -> rev or nil
|
169
|
-
# revisions.delete(oid) -> rev or nil
|
170
|
-
#
|
171
|
-
# Deletes a revision from the document, either by index or by specifying the revision object
|
172
|
-
# itself.
|
173
|
-
#
|
174
|
-
# Returns the deleted revision object, or +nil+ if the index was out of range or no matching
|
175
|
-
# revision was found.
|
176
|
-
#
|
177
|
-
# Regarding the index: The oldest revision has index 0 and the current revision the highest
|
178
|
-
# index!
|
179
|
-
def delete(index_or_rev)
|
180
|
-
if @revisions.length == 1
|
181
|
-
raise HexaPDF::Error, "A document must have a least one revision, can't delete last one"
|
182
|
-
elsif index_or_rev.kind_of?(Integer)
|
183
|
-
@revisions.delete_at(index_or_rev)
|
184
|
-
else
|
185
|
-
@revisions.delete(index_or_rev)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
301
|
# :call-seq:
|
190
302
|
# revisions.merge(range = 0..-1) -> revisions
|
191
303
|
#
|
@@ -206,17 +318,6 @@ module HexaPDF
|
|
206
318
|
self
|
207
319
|
end
|
208
320
|
|
209
|
-
# :call-seq:
|
210
|
-
# revisions.each {|rev| block } -> revisions
|
211
|
-
# revisions.each -> Enumerator
|
212
|
-
#
|
213
|
-
# Iterates over all revisions from oldest to current one.
|
214
|
-
def each(&block)
|
215
|
-
return to_enum(__method__) unless block_given?
|
216
|
-
@revisions.each(&block)
|
217
|
-
self
|
218
|
-
end
|
219
|
-
|
220
321
|
end
|
221
322
|
|
222
323
|
end
|
data/lib/hexapdf/serializer.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# This file is part of HexaPDF.
|
5
5
|
#
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
-
# Copyright (C) 2014-
|
7
|
+
# Copyright (C) 2014-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/stream.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# This file is part of HexaPDF.
|
5
5
|
#
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
-
# Copyright (C) 2014-
|
7
|
+
# Copyright (C) 2014-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
|