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
@@ -0,0 +1,397 @@
|
|
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'
|
38
|
+
|
39
|
+
module HexaPDF
|
40
|
+
class Document
|
41
|
+
|
42
|
+
# This class provides methods for working with classes in the HexaPDF::Layout module.
|
43
|
+
#
|
44
|
+
# Often times the layout related classes are used through HexaPDF::Composer which makes it easy
|
45
|
+
# to create documents. However, sometimes one wants to have a bit more control or do something
|
46
|
+
# special and use the HexaPDF::Layout classes directly. This is possible but it is better to use
|
47
|
+
# those classes through an instance of this classs because it makes it more convenient and ties
|
48
|
+
# everything together. Incidentally, HexaPDF::Composer relies on this class for a good part of
|
49
|
+
# its work.
|
50
|
+
#
|
51
|
+
#
|
52
|
+
# == Boxes
|
53
|
+
#
|
54
|
+
# The main focus of the class is on providing convenience methods for creating box objects. The
|
55
|
+
# most often used box classes like HexaPDF::Layout::TextBox or HexaPDF::Layout::ImagebBox can be
|
56
|
+
# created through dedicated methods.
|
57
|
+
#
|
58
|
+
# Other, more general boxes don't have their own method but can be created through the general
|
59
|
+
# #box method.
|
60
|
+
#
|
61
|
+
#
|
62
|
+
# == Box Styles
|
63
|
+
#
|
64
|
+
# All box creation methods accept HexaPDF::Layout::Style objects or names for style objects
|
65
|
+
# (defined via #style). This allows one to predefine certain styles (like first level heading,
|
66
|
+
# second level heading, paragraph, ...) and consistently use them throughout the document
|
67
|
+
# creation process.
|
68
|
+
#
|
69
|
+
# One style property, HexaPDF::Layout::Style#font, is handled specially:
|
70
|
+
#
|
71
|
+
# * If no font is set on a style, the font "Times" is automatically set because otherwise there
|
72
|
+
# would be problems with text drawing operations (font is the only style property that has no
|
73
|
+
# valid default value).
|
74
|
+
#
|
75
|
+
# * Standard style objects only allow font wrapper objects to be set via the
|
76
|
+
# HexaPDF::Layout::Style#font method. This class makes usage easier by allowing strings or an
|
77
|
+
# array [name, options_hash] to be used, like with e.g Content::Canvas#font. So to use
|
78
|
+
# Helvetica as font, one could just do:
|
79
|
+
#
|
80
|
+
# style.font = 'Helvetica'
|
81
|
+
#
|
82
|
+
# And if Helvetica in its bold variant should be used it would be:
|
83
|
+
#
|
84
|
+
# style.font = ['Helvetica', variant: :bold]
|
85
|
+
#
|
86
|
+
class Layout
|
87
|
+
|
88
|
+
# This class is used when a box can contain child boxes and the creation of such boxes should
|
89
|
+
# be seemlessly doable when creating the parent node. It is yieled, for example, by Layout#box
|
90
|
+
# to collect the children for the created box.
|
91
|
+
#
|
92
|
+
# A box can be added to the list of collected children in the following ways:
|
93
|
+
#
|
94
|
+
# #<<:: This appends the given box to the list.
|
95
|
+
#
|
96
|
+
# text_box, formatted_text_box, image_box, ...:: Any method accepted by the Layout class.
|
97
|
+
#
|
98
|
+
# text, formatted_text, image, ...:: Any method accepted by the Layout class without the _box
|
99
|
+
# suffix.
|
100
|
+
#
|
101
|
+
# list, column, ...:: Any name registered for the configuration option +layout.boxes.map+.
|
102
|
+
#
|
103
|
+
# Example:
|
104
|
+
#
|
105
|
+
# document.layout.box(:list) do |list|
|
106
|
+
# list.text_box("Some text here") # layout method
|
107
|
+
# list.image(image_path) # layout method without _box suffix
|
108
|
+
# list.column(columns: 3) do |column| # registered box name
|
109
|
+
# column.text("Text in column")
|
110
|
+
# column << document.layout.lorem_ipsum_box # adding a Box instance
|
111
|
+
# end
|
112
|
+
# end
|
113
|
+
class ChildrenCollector
|
114
|
+
|
115
|
+
# Creates a children collector, yields it and then returns the collected children.
|
116
|
+
def self.collect(layout)
|
117
|
+
collector = new(layout)
|
118
|
+
yield(collector)
|
119
|
+
collector.children
|
120
|
+
end
|
121
|
+
|
122
|
+
# The collected children
|
123
|
+
attr_reader :children
|
124
|
+
|
125
|
+
# Create a new ChildrenCollector for the given +layout+ (a HexaPDF::Document::Layout)
|
126
|
+
# instance.
|
127
|
+
def initialize(layout)
|
128
|
+
@layout = layout
|
129
|
+
@layout_boxes_map = layout.instance_variable_get(:@document).config['layout.boxes.map']
|
130
|
+
@children = []
|
131
|
+
end
|
132
|
+
|
133
|
+
# :nodoc:
|
134
|
+
def method_missing(name, *args, **kwargs, &block)
|
135
|
+
if @layout.respond_to?(name)
|
136
|
+
@children << @layout.send(name, *args, **kwargs, &block)
|
137
|
+
elsif @layout.respond_to?("#{name}_box")
|
138
|
+
@children << @layout.send("#{name}_box", *args, **kwargs, &block)
|
139
|
+
elsif @layout_boxes_map.key?(name)
|
140
|
+
@children << @layout.box(name, *args, **kwargs, &block)
|
141
|
+
else
|
142
|
+
super
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# :nodoc:
|
147
|
+
def respond_to_missing?(name, _private)
|
148
|
+
@layout.respond_to?(name) ||
|
149
|
+
@layout.respond_to?("#{name}_box") ||
|
150
|
+
@layout_boxes_map.key?(name) ||
|
151
|
+
super
|
152
|
+
end
|
153
|
+
|
154
|
+
# Appends the given box to the list of collected children.
|
155
|
+
def <<(box)
|
156
|
+
@children << box
|
157
|
+
end
|
158
|
+
|
159
|
+
# Yields a ChildrenCollector instance and adds the collected children as a single array to
|
160
|
+
# the list of collected children.
|
161
|
+
def multiple(&block)
|
162
|
+
@children << self.class.collect(@layout, &block)
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
# The mapping of style name (a Symbol) to HexaPDF::Layout::Style instance.
|
168
|
+
attr_reader :styles
|
169
|
+
|
170
|
+
# Creates a new Layout object for the given PDF document.
|
171
|
+
def initialize(document)
|
172
|
+
@document = document
|
173
|
+
@styles = {base: HexaPDF::Layout::Style.new}
|
174
|
+
end
|
175
|
+
|
176
|
+
# :call-seq:
|
177
|
+
# layout.style(name) -> style
|
178
|
+
# layout.style(name, base: :base, **properties) -> style
|
179
|
+
#
|
180
|
+
# Creates or updates the HexaPDF::Layout::Style object called +name+ with the given property
|
181
|
+
# values and returns it.
|
182
|
+
#
|
183
|
+
# This method allows convenient access to the stored styles and to update them. Such styles
|
184
|
+
# can then be used by name in the various box creation methods, e.g. #text_box or #image_box.
|
185
|
+
#
|
186
|
+
# If neither +base+ nor any style properties are specified, the style +name+ is just returned.
|
187
|
+
#
|
188
|
+
# If the style +name+ does not exist yet and the argument +base+ specifies the name of another
|
189
|
+
# style, that style is duplicated and used as basis for the style. This also means that the
|
190
|
+
# referenced +base+ style needs be defined first!
|
191
|
+
#
|
192
|
+
# The special name :base should be used for setting the base style which is used when no
|
193
|
+
# specific style is set.
|
194
|
+
#
|
195
|
+
# Note that the style property 'font' is handled specially, see the class documentation for
|
196
|
+
# details.
|
197
|
+
#
|
198
|
+
# Example:
|
199
|
+
#
|
200
|
+
# layout.style(:base, font_size: 12, leading: 1.2)
|
201
|
+
# layout.style(:header, font: 'Helvetica', fill_color: "008")
|
202
|
+
# layout.style(:header1, base: :header, font_size: 30)
|
203
|
+
#
|
204
|
+
# See: HexaPDF::Layout::Style
|
205
|
+
def style(name, base: :base, **properties)
|
206
|
+
style = @styles[name] ||= (@styles.key?(base) ? @styles[base].dup : HexaPDF::Layout::Style.new)
|
207
|
+
style.update(**properties) unless properties.empty?
|
208
|
+
style
|
209
|
+
end
|
210
|
+
|
211
|
+
# Creates the named box and returns it.
|
212
|
+
#
|
213
|
+
# The +name+ argument refers to the registered name of the box class that is looked up in the
|
214
|
+
# 'layout.boxes.map' configuration option. The +box_options+ are passed as-is to the
|
215
|
+
# initialization method of that box class
|
216
|
+
#
|
217
|
+
# If a block is provided, a ChildrenCollector is yielded and the collected children are passed
|
218
|
+
# to the box initialization method via the :children keyword argument.
|
219
|
+
#
|
220
|
+
# See #text_box for details on +width+, +height+ and +style+ (note that there is no
|
221
|
+
# +style_properties+ argument).
|
222
|
+
#
|
223
|
+
# Example:
|
224
|
+
#
|
225
|
+
# doc.layout.box(:column, columns: 2, gap: 15) # => column_box_instance
|
226
|
+
# doc.layout.box(:column) do |column| # column box with one child
|
227
|
+
# column.lorem_ipsum
|
228
|
+
# end
|
229
|
+
def box(name, width: 0, height: 0, style: nil, **box_options, &block)
|
230
|
+
if block_given? && !box_options.key?(:children)
|
231
|
+
box_options[:children] = ChildrenCollector.collect(self, &block)
|
232
|
+
end
|
233
|
+
box_class_for_name(name).new(width: width, height: height,
|
234
|
+
style: retrieve_style(style), **box_options)
|
235
|
+
end
|
236
|
+
|
237
|
+
# Creates a HexaPDF::Layout::TextBox for the given text.
|
238
|
+
#
|
239
|
+
# This method is of the two main methods for creating text boxes, the other being
|
240
|
+
# #formatted_text_box.
|
241
|
+
#
|
242
|
+
# +width+, +height+::
|
243
|
+
# The arguments +width+ and +height+ are used as constraints and are respected when
|
244
|
+
# fitting the box. The default value of 0 means that no constraints are set.
|
245
|
+
#
|
246
|
+
# +style+, +style_properties+::
|
247
|
+
# The box and the text are styled using the given +style+. This can either be a style name
|
248
|
+
# set via #style or anything HexaPDF::Layout::Style::create accepts. If any additional
|
249
|
+
# +style_properties+ are specified, the style is duplicated and the additional styles are
|
250
|
+
# applied.
|
251
|
+
#
|
252
|
+
# +box_style+::
|
253
|
+
# Sometimes it is necessary for the box to have a different style than the text, e.g. when
|
254
|
+
# using overlays. In such a case use +box_style+ for specifiying the style of the box (a
|
255
|
+
# style name set via #style or anything HexaPDF::Layout::Style::create accepts).
|
256
|
+
#
|
257
|
+
# The +style+ together with the +style_properties+ will be used for the text style.
|
258
|
+
#
|
259
|
+
# Examples:
|
260
|
+
#
|
261
|
+
# layout.text("Test " * 15)
|
262
|
+
# layout.text("Now " * 7, width: 100)
|
263
|
+
# layout.text("Another test", font_size: 15, fill_color: "green")
|
264
|
+
# layout.text("Different box style", fill_color: 'white', box_style: {
|
265
|
+
# underlays: [->(c, b) { c.rectangle(0, 0, b.content_width, b.content_height).fill }]
|
266
|
+
# })
|
267
|
+
#
|
268
|
+
# See: #formatted_text_box, HexaPDF::Layout::TextBox, HexaPDF::Layout::TextFragment
|
269
|
+
def text_box(text, width: 0, height: 0, style: nil, box_style: nil, **style_properties)
|
270
|
+
style = retrieve_style(style, style_properties)
|
271
|
+
box_style = (box_style ? retrieve_style(box_style) : style)
|
272
|
+
box_class_for_name(:text).new(items: [HexaPDF::Layout::TextFragment.create(text, style)],
|
273
|
+
width: width, height: height, style: box_style)
|
274
|
+
end
|
275
|
+
|
276
|
+
# Creates a HexaPDF::Layout::TextBox like #text_box but allows parts of the text to be
|
277
|
+
# formatted differently.
|
278
|
+
#
|
279
|
+
# The argument +data+ needs to be an array of String and/or Hash objects:
|
280
|
+
#
|
281
|
+
# * A String object is treated like {text: data}.
|
282
|
+
#
|
283
|
+
# * Hashes can contain any style properties and the following special keys:
|
284
|
+
#
|
285
|
+
# text:: The text to be formatted.
|
286
|
+
#
|
287
|
+
# link:: A URL that should be linked to. If no text is provided but a link, the link is used
|
288
|
+
# as text.
|
289
|
+
#
|
290
|
+
# style:: The style to be use as base style instead of the style created from the +style+
|
291
|
+
# and +style_properties+ arguments. See HexaPDF::Layout::Style::create for allowed
|
292
|
+
# values.
|
293
|
+
#
|
294
|
+
# If any style properties are set, the used style is duplicated and the additional
|
295
|
+
# properties applied.
|
296
|
+
#
|
297
|
+
# See #text_box for details on +width+, +height+, +style+, +style_properties+ and +box_style+.
|
298
|
+
#
|
299
|
+
# Examples:
|
300
|
+
#
|
301
|
+
# layout.formatted_text_box(["Some string"])
|
302
|
+
# layout.formatted_text_box(["Some ", {text: "string", fill_color: 128}])
|
303
|
+
# layout.formatted_text_box(["Some ", {link: "https://example.com",
|
304
|
+
# fill_color: 'blue', text: "Example"}])
|
305
|
+
# layout.formatted_text_box(["Some ", {text: "string", style: {font_size: 20}}])
|
306
|
+
#
|
307
|
+
# See: #text_box, HexaPDF::Layout::TextBox, HexaPDF::Layout::TextFragment
|
308
|
+
def formatted_text_box(data, width: 0, height: 0, style: nil, box_style: nil, **style_properties)
|
309
|
+
style = retrieve_style(style, style_properties)
|
310
|
+
box_style = (box_style ? retrieve_style(box_style) : style)
|
311
|
+
data.map! do |hash|
|
312
|
+
if hash.kind_of?(String)
|
313
|
+
HexaPDF::Layout::TextFragment.create(hash, style)
|
314
|
+
else
|
315
|
+
link = hash.delete(:link)
|
316
|
+
(hash[:overlays] ||= []) << [:link, {uri: link}] if link
|
317
|
+
text = hash.delete(:text) || link || ""
|
318
|
+
HexaPDF::Layout::TextFragment.create(text, retrieve_style(hash.delete(:style) || style, hash))
|
319
|
+
end
|
320
|
+
end
|
321
|
+
box_class_for_name(:text).new(items: data, width: width, height: height, style: box_style)
|
322
|
+
end
|
323
|
+
|
324
|
+
# Creates a HexaPDF::Layout::ImageBox for the given image.
|
325
|
+
#
|
326
|
+
# The +file+ argument can be anything that is accepted by HexaPDF::Document::Images#add or a
|
327
|
+
# HexaPDF::Type::Form object.
|
328
|
+
#
|
329
|
+
# See #text_box for details on +width+, +height+, +style+ and +style_properties+.
|
330
|
+
#
|
331
|
+
# Examples:
|
332
|
+
#
|
333
|
+
# layout.image_box(machu_picchu, border: {width: 3})
|
334
|
+
# layout.image_box(machu_picchu, height: 30)
|
335
|
+
#
|
336
|
+
# See: HexaPDF::Layout::ImageBox
|
337
|
+
def image_box(file, width: 0, height: 0, style: nil, **style_properties)
|
338
|
+
style = retrieve_style(style, style_properties)
|
339
|
+
image = file.kind_of?(HexaPDF::Stream) ? file : @document.images.add(file)
|
340
|
+
box_class_for_name(:image).new(image: image, width: width, height: height, style: style)
|
341
|
+
end
|
342
|
+
|
343
|
+
# :nodoc:
|
344
|
+
LOREM_IPSUM = [
|
345
|
+
"Lorem ipsum dolor sit amet, con\u{00AD}sectetur adipis\u{00AD}cing elit, sed " \
|
346
|
+
"do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
347
|
+
"Ut enim ad minim veniam, quis nostrud exer\u{00AD}citation ullamco laboris nisi ut " \
|
348
|
+
"aliquip ex ea commodo consequat. ",
|
349
|
+
"Duis aute irure dolor in reprehen\u{00AD}derit in voluptate velit esse cillum dolore " \
|
350
|
+
"eu fugiat nulla pariatur. ",
|
351
|
+
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " \
|
352
|
+
"mollit anim id est laborum.",
|
353
|
+
]
|
354
|
+
|
355
|
+
# Uses #text_box to create +count+ paragraphs of lorem ipsum text.
|
356
|
+
#
|
357
|
+
# The +text_box_properties+ arguments are passed as is to #text_box.
|
358
|
+
def lorem_ipsum_box(sentences: 4, count: 1, **text_box_properties)
|
359
|
+
text_box(([LOREM_IPSUM[0, sentences].join(" ")] * count).join("\n\n"), **text_box_properties)
|
360
|
+
end
|
361
|
+
|
362
|
+
private
|
363
|
+
|
364
|
+
# Returns the configured box class for the given +name+.
|
365
|
+
def box_class_for_name(name)
|
366
|
+
@document.config.constantize('layout.boxes.map', name) do
|
367
|
+
raise HexaPDF::Error, "Couldn't retrieve box class #{name} from configuration"
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
# Retrieves the appropriate HexaPDF::Layout::Style object based on the +style+ and +properties+
|
372
|
+
# arguments.
|
373
|
+
#
|
374
|
+
# The +style+ argument specifies the style to retrieve. It can either be a registered style
|
375
|
+
# name (see #style), a hash with style properties or +nil+. In the latter case the registered
|
376
|
+
# style :base is used
|
377
|
+
#
|
378
|
+
# If the +properties+ hash is not empty, the retrieved style is duplicated and the properties
|
379
|
+
# hash is applied to it.
|
380
|
+
#
|
381
|
+
# Finally, a default font is set if necessary to ensure that the style object works in all
|
382
|
+
# cases.
|
383
|
+
def retrieve_style(style, properties = nil)
|
384
|
+
style = HexaPDF::Layout::Style.create(@styles[style] || style || @styles[:base])
|
385
|
+
style = style.dup.update(**properties) unless properties.nil? || properties.empty?
|
386
|
+
style.font('Times') unless style.font?
|
387
|
+
unless style.font.respond_to?(:pdf_object)
|
388
|
+
name, options = *style.font
|
389
|
+
style.font(@document.fonts.add(name, **(options || {})))
|
390
|
+
end
|
391
|
+
style
|
392
|
+
end
|
393
|
+
|
394
|
+
end
|
395
|
+
|
396
|
+
end
|
397
|
+
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
|
@@ -101,6 +101,22 @@ module HexaPDF
|
|
101
101
|
@document.catalog.pages.insert_page(index, page)
|
102
102
|
end
|
103
103
|
|
104
|
+
# :call-seq:
|
105
|
+
# pages.move(page, to_index)
|
106
|
+
# pages.move(index, to_index)
|
107
|
+
#
|
108
|
+
# Moves the given page or the page at the position specified by the zero-based index to the
|
109
|
+
# +to_index+ position.
|
110
|
+
#
|
111
|
+
# If the page that should be moved, doesn't exist or is invalid, an error is raised.
|
112
|
+
#
|
113
|
+
# Negative indices count backwards from the end, i.e. -1 is the last page. When using a
|
114
|
+
# negative index, the page will be moved after that element. So using an index of -1 will
|
115
|
+
# move the page after the last page.
|
116
|
+
def move(page, to_index)
|
117
|
+
@document.catalog.pages.move_page(page, to_index)
|
118
|
+
end
|
119
|
+
|
104
120
|
# Deletes the given page object from the document's page tree and the document.
|
105
121
|
#
|
106
122
|
# Also see: HexaPDF::Type::PageTreeNode#delete_page
|
@@ -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
|
@@ -239,7 +239,7 @@ module HexaPDF
|
|
239
239
|
signature[:M] = Time.now
|
240
240
|
|
241
241
|
io = if file_or_io.kind_of?(String)
|
242
|
-
File.open(file_or_io, '
|
242
|
+
File.open(file_or_io, 'wb+')
|
243
243
|
else
|
244
244
|
file_or_io
|
245
245
|
end
|
@@ -247,8 +247,9 @@ module HexaPDF
|
|
247
247
|
# Save the current state so that we can determine the correct /ByteRange value and set the
|
248
248
|
# values
|
249
249
|
handler.finalize_objects(signature_field, signature)
|
250
|
-
section = @document.write(io, incremental: true, **write_options)
|
251
|
-
data = section.map {|oid, _gen, entry| [entry.pos, oid] if entry.in_use? }.compact.sort
|
250
|
+
start_xref_position, section = @document.write(io, incremental: true, **write_options)
|
251
|
+
data = section.map {|oid, _gen, entry| [entry.pos, oid] if entry.in_use? }.compact.sort <<
|
252
|
+
[start_xref_position, nil]
|
252
253
|
index = data.index {|_pos, oid| oid == signature.oid }
|
253
254
|
signature_offset = data[index][0]
|
254
255
|
signature_length = data[index + 1][0] - data[index][0]
|
data/lib/hexapdf/document.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
|
@@ -106,6 +106,8 @@ module HexaPDF
|
|
106
106
|
autoload(:Images, 'hexapdf/document/images')
|
107
107
|
autoload(:Files, 'hexapdf/document/files')
|
108
108
|
autoload(:Signatures, 'hexapdf/document/signatures')
|
109
|
+
autoload(:Destinations, 'hexapdf/document/destinations')
|
110
|
+
autoload(:Layout, 'hexapdf/document/layout')
|
109
111
|
|
110
112
|
# :call-seq:
|
111
113
|
# Document.open(filename, **docargs) -> doc
|
@@ -184,22 +186,9 @@ module HexaPDF
|
|
184
186
|
# For references to unknown objects, +nil+ is returned but free objects are represented by a
|
185
187
|
# PDF Null object, not by +nil+!
|
186
188
|
#
|
187
|
-
# See:
|
189
|
+
# See: Revisions#object
|
188
190
|
def object(ref)
|
189
|
-
|
190
|
-
while i >= 0
|
191
|
-
return @revisions[i].object(ref) if @revisions[i].object?(ref)
|
192
|
-
i -= 1
|
193
|
-
end
|
194
|
-
nil
|
195
|
-
end
|
196
|
-
|
197
|
-
# Dereferences the given object.
|
198
|
-
#
|
199
|
-
# Return the object itself if it is not a reference, or the indirect object specified by the
|
200
|
-
# reference.
|
201
|
-
def deref(obj)
|
202
|
-
obj.kind_of?(Reference) ? object(obj) : obj
|
191
|
+
@revisions.object(ref)
|
203
192
|
end
|
204
193
|
|
205
194
|
# :call-seq:
|
@@ -212,74 +201,51 @@ module HexaPDF
|
|
212
201
|
# Even though this method might return +true+ for some references, #object may return +nil+
|
213
202
|
# because this method takes *all* revisions into account. Also see the discussion on #each for
|
214
203
|
# more information.
|
204
|
+
#
|
205
|
+
# See: Revisions#object?
|
215
206
|
def object?(ref)
|
216
|
-
@revisions.
|
207
|
+
@revisions.object?(ref)
|
208
|
+
end
|
209
|
+
|
210
|
+
# Dereferences the given object.
|
211
|
+
#
|
212
|
+
# Return the object itself if it is not a reference, or the indirect object specified by the
|
213
|
+
# reference.
|
214
|
+
def deref(obj)
|
215
|
+
obj.kind_of?(Reference) ? object(obj) : obj
|
217
216
|
end
|
218
217
|
|
219
218
|
# :call-seq:
|
220
|
-
# doc.add(obj,
|
219
|
+
# doc.add(obj, **wrap_opts) -> indirect_object
|
221
220
|
#
|
222
|
-
# Adds the object to the
|
223
|
-
# object.
|
221
|
+
# Adds the object to the document and returns the wrapped indirect object.
|
224
222
|
#
|
225
223
|
# The object can either be a native Ruby object (Hash, Array, Integer, ...) or a
|
226
224
|
# HexaPDF::Object. If it is not the latter, #wrap is called with the object and the
|
227
225
|
# additional keyword arguments.
|
228
226
|
#
|
229
|
-
#
|
230
|
-
|
231
|
-
def add(obj, revision: :current, **wrap_opts)
|
227
|
+
# See: Revisions#add_object
|
228
|
+
def add(obj, **wrap_opts)
|
232
229
|
obj = wrap(obj, **wrap_opts) unless obj.kind_of?(HexaPDF::Object)
|
233
230
|
|
234
|
-
revision = (revision == :current ? @revisions.current : @revisions.revision(revision))
|
235
|
-
if revision.nil?
|
236
|
-
raise ArgumentError, "Invalid revision index specified"
|
237
|
-
end
|
238
|
-
|
239
231
|
if obj.document? && obj.document != self
|
240
232
|
raise HexaPDF::Error, "Can't add object that is already attached to another document"
|
241
233
|
end
|
242
234
|
obj.document = self
|
243
235
|
|
244
|
-
|
245
|
-
if rev_obj.equal?(obj)
|
246
|
-
return obj
|
247
|
-
else
|
248
|
-
raise HexaPDF::Error, "Can't add object because the specified revision already has " \
|
249
|
-
"an object with object number #{obj.oid}"
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
obj.oid = @revisions.map(&:next_free_oid).max unless obj.indirect?
|
254
|
-
|
255
|
-
revision.add(obj)
|
236
|
+
@revisions.add_object(obj)
|
256
237
|
end
|
257
238
|
|
258
239
|
# :call-seq:
|
259
|
-
# doc.delete(ref
|
260
|
-
# doc.delete(oid
|
240
|
+
# doc.delete(ref)
|
241
|
+
# doc.delete(oid)
|
261
242
|
#
|
262
243
|
# Deletes the indirect object specified by an exact reference or by an object number from the
|
263
244
|
# document.
|
264
245
|
#
|
265
|
-
#
|
266
|
-
|
267
|
-
|
268
|
-
#
|
269
|
-
# :all:: Delete the object from all revisions.
|
270
|
-
# :current:: Delete the object only from the current revision.
|
271
|
-
#
|
272
|
-
# mark_as_free:: If +true+, objects are only marked as free objects instead of being actually
|
273
|
-
# deleted.
|
274
|
-
def delete(ref, revision: :all, mark_as_free: true)
|
275
|
-
case revision
|
276
|
-
when :current
|
277
|
-
@revisions.current.delete(ref, mark_as_free: mark_as_free)
|
278
|
-
when :all
|
279
|
-
@revisions.each {|rev| rev.delete(ref, mark_as_free: mark_as_free) }
|
280
|
-
else
|
281
|
-
raise ArgumentError, "Unsupported option revision: #{revision}"
|
282
|
-
end
|
246
|
+
# See: Revisions#delete_object
|
247
|
+
def delete(ref)
|
248
|
+
@revisions.delete_object(ref)
|
283
249
|
end
|
284
250
|
|
285
251
|
# :call-seq:
|
@@ -414,42 +380,20 @@ module HexaPDF
|
|
414
380
|
end
|
415
381
|
|
416
382
|
# :call-seq:
|
417
|
-
# doc.each(only_current: true, only_loaded: false) {|obj| block }
|
418
|
-
# doc.each(only_current: true, only_loaded: false) {|obj, rev| block }
|
383
|
+
# doc.each(only_current: true, only_loaded: false) {|obj| block }
|
384
|
+
# doc.each(only_current: true, only_loaded: false) {|obj, rev| block }
|
419
385
|
# doc.each(only_current: true, only_loaded: false) -> Enumerator
|
420
386
|
#
|
421
|
-
#
|
422
|
-
# object in the PDF document. The block may either accept only the object or the object and the
|
423
|
-
# revision it is in.
|
424
|
-
#
|
425
|
-
# By default, only the current version of each object is returned which implies that each object
|
426
|
-
# number is yielded exactly once. If the +only_current+ option is +false+, all stored objects
|
427
|
-
# from newest to oldest are returned, not only the current version of each object.
|
387
|
+
# Yields every object and the revision it is in.
|
428
388
|
#
|
429
|
-
#
|
430
|
-
# revisions
|
389
|
+
# If +only_current+ is +true+, only the current version of each object is yielded, otherwise
|
390
|
+
# all objects from all revisions.
|
431
391
|
#
|
432
|
-
#
|
433
|
-
# two (different) objects with oid/gen [3,0].
|
392
|
+
# If +only_loaded+ is +true+, only the already loaded objects are yielded.
|
434
393
|
#
|
435
|
-
#
|
436
|
-
# generation numbers in different revisions, e.g. one object with oid/gen [3,0] and one with
|
437
|
-
# oid/gen [3,1].
|
394
|
+
# For details see Revisions#each_object
|
438
395
|
def each(only_current: true, only_loaded: false, &block)
|
439
|
-
|
440
|
-
return to_enum(__method__, only_current: only_current, only_loaded: only_loaded)
|
441
|
-
end
|
442
|
-
|
443
|
-
yield_rev = (block.arity == 2)
|
444
|
-
oids = {}
|
445
|
-
@revisions.reverse_each do |rev|
|
446
|
-
rev.each(only_loaded: only_loaded) do |obj|
|
447
|
-
next if only_current && oids.include?(obj.oid)
|
448
|
-
(yield_rev ? yield(obj, rev) : yield(obj))
|
449
|
-
oids[obj.oid] = true
|
450
|
-
end
|
451
|
-
end
|
452
|
-
self
|
396
|
+
@revisions.each_object(only_current: only_current, only_loaded: only_loaded, &block)
|
453
397
|
end
|
454
398
|
|
455
399
|
# :call-seq:
|
@@ -529,6 +473,18 @@ module HexaPDF
|
|
529
473
|
@fonts ||= Fonts.new(self)
|
530
474
|
end
|
531
475
|
|
476
|
+
# Returns the Destinations object that provides convenience methods for working with destination
|
477
|
+
# objects.
|
478
|
+
def destinations
|
479
|
+
@destinations ||= Destinations.new(self)
|
480
|
+
end
|
481
|
+
|
482
|
+
# Returns the Layout object that provides convenience methods for working with the
|
483
|
+
# HexaPDF::Layout classes for document layout.
|
484
|
+
def layout
|
485
|
+
@layout ||= Layout.new(self)
|
486
|
+
end
|
487
|
+
|
532
488
|
# Returns the main AcroForm object for dealing with interactive forms.
|
533
489
|
#
|
534
490
|
# See HexaPDF::Type::Catalog#acro_form for details on the arguments.
|
@@ -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
|