hexapdf 0.33.0 → 0.34.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 +42 -1
- data/examples/026-optional_content.rb +55 -0
- data/examples/027-composer_optional_content.rb +83 -0
- data/lib/hexapdf/cli/command.rb +7 -1
- data/lib/hexapdf/cli/fonts.rb +1 -1
- data/lib/hexapdf/cli/inspect.rb +2 -4
- data/lib/hexapdf/composer.rb +2 -1
- data/lib/hexapdf/configuration.rb +21 -1
- data/lib/hexapdf/content/canvas.rb +52 -0
- data/lib/hexapdf/content/operator.rb +2 -0
- data/lib/hexapdf/dictionary.rb +1 -0
- data/lib/hexapdf/dictionary_fields.rb +1 -2
- data/lib/hexapdf/digital_signature/verification_result.rb +1 -2
- data/lib/hexapdf/document/layout.rb +3 -0
- data/lib/hexapdf/document/pages.rb +1 -1
- data/lib/hexapdf/document.rb +7 -0
- data/lib/hexapdf/encryption/ruby_aes.rb +10 -20
- data/lib/hexapdf/layout/box.rb +23 -3
- data/lib/hexapdf/layout/column_box.rb +2 -1
- data/lib/hexapdf/layout/frame.rb +23 -6
- data/lib/hexapdf/layout/inline_box.rb +20 -9
- data/lib/hexapdf/layout/list_box.rb +34 -20
- data/lib/hexapdf/layout/page_style.rb +2 -1
- data/lib/hexapdf/layout/style.rb +46 -6
- data/lib/hexapdf/layout/table_box.rb +9 -7
- data/lib/hexapdf/layout/text_box.rb +9 -2
- data/lib/hexapdf/layout/text_fragment.rb +28 -2
- data/lib/hexapdf/layout/text_layouter.rb +21 -5
- data/lib/hexapdf/stream.rb +1 -2
- data/lib/hexapdf/type/actions/set_ocg_state.rb +86 -0
- data/lib/hexapdf/type/actions.rb +1 -0
- data/lib/hexapdf/type/annotations/text.rb +1 -2
- data/lib/hexapdf/type/catalog.rb +10 -1
- data/lib/hexapdf/type/cid_font.rb +15 -1
- data/lib/hexapdf/type/form.rb +75 -5
- data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
- data/lib/hexapdf/type/optional_content_group.rb +370 -0
- data/lib/hexapdf/type/optional_content_membership.rb +63 -0
- data/lib/hexapdf/type/optional_content_properties.rb +158 -0
- data/lib/hexapdf/type/page.rb +27 -11
- data/lib/hexapdf/type/page_label.rb +4 -8
- data/lib/hexapdf/type.rb +4 -0
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +0 -1
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/content/test_canvas.rb +49 -0
- data/test/hexapdf/document/test_layout.rb +7 -2
- data/test/hexapdf/document/test_pages.rb +6 -6
- data/test/hexapdf/layout/test_box.rb +13 -4
- data/test/hexapdf/layout/test_frame.rb +13 -1
- data/test/hexapdf/layout/test_inline_box.rb +17 -8
- data/test/hexapdf/layout/test_list_box.rb +48 -31
- data/test/hexapdf/layout/test_style.rb +10 -0
- data/test/hexapdf/layout/test_table_box.rb +32 -26
- data/test/hexapdf/layout/test_text_box.rb +8 -0
- data/test/hexapdf/layout/test_text_fragment.rb +33 -0
- data/test/hexapdf/layout/test_text_layouter.rb +32 -5
- data/test/hexapdf/test_composer.rb +10 -0
- data/test/hexapdf/test_dictionary.rb +10 -0
- data/test/hexapdf/test_document.rb +4 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
- data/test/hexapdf/type/test_catalog.rb +11 -0
- data/test/hexapdf/type/test_form.rb +119 -0
- data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
- data/test/hexapdf/type/test_optional_content_group.rb +158 -0
- data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
- data/test/hexapdf/type/test_page.rb +2 -2
- metadata +14 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 00aaef323df26b1a17c6e4ee39787c92037e8ae887713b28c3674962fcb6ac26
|
|
4
|
+
data.tar.gz: a46ecda2514bc5c044d115370f66402fc22ad3f8c8dfa1741e057b6849a6b952
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a15e468bdc852fd4c16286ba0e4829fcd3fb3be64aa48c429246216fbfe1c856cb8e155bfefa83c47b99246e7161f20a1de54769aa222dbcdfdb25f8be777643
|
|
7
|
+
data.tar.gz: d75048ff9d77601d93893cceb0c73673410695e3ea381e17d27de8c92d7de3d29d2ed467e44df6362dd28d3ee374a8e5710e5f1323393ee2e4104cdcecef1112
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
## 0.34.0 - 2023-10-22
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
* Support for optional content groups (layers)
|
|
6
|
+
* Support for reference XObjects
|
|
7
|
+
* Basic support for group XObjects
|
|
8
|
+
* [HexaPDF::Layout::Style#fill_horizontal] for allowing a text fragment to fill
|
|
9
|
+
the remaining space of line
|
|
10
|
+
* [HexaPDF::Layout::TextFragment#text] and [HexaPDF::Layout::TextBox#text] for
|
|
11
|
+
retrieving the text represented by the stored items
|
|
12
|
+
* [HexaPDF::Content::Canvas#pos] for retrieving untransformed positions
|
|
13
|
+
* [HexaPDF::Type::CIDFont::CIDSystemInfo] type class
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
* [HexaPDF::Composer#draw_box] to return the last drawn box
|
|
18
|
+
* [HexaPDF::Layout::Style::LinkLayer] to support arbitrary actions
|
|
19
|
+
* [HexaPDF::Layout::Frame::new] (and adapted other layout classes) to accept a
|
|
20
|
+
context argument (a page or Form XObject instance)
|
|
21
|
+
* [HexaPDF::Layout::ListBox] to use its 'fill_color' style property for the item
|
|
22
|
+
marker color
|
|
23
|
+
* [HexaPDF::Layout::Frame::FitResult#draw] to use optional content groups for
|
|
24
|
+
debug output
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
* [HexaPDF::Document::Pages#add_labelling_range] to add a correct entry for
|
|
29
|
+
the default range starting at page 1
|
|
30
|
+
* [HexaPDF::Type::Page#flatten_annotations] to correctly handle scaled
|
|
31
|
+
appearances
|
|
32
|
+
* Using an unknown style name in [HexaPDF:Document::Layout] method by providing
|
|
33
|
+
a useful error message
|
|
34
|
+
* [HexaPDF::Layout::Box::new] to ensure that the properties attribute is always
|
|
35
|
+
a hash
|
|
36
|
+
* [HexaPDF::Layout::ListBox] to work correctly if the marker height is larger
|
|
37
|
+
than the item content height
|
|
38
|
+
* [HexaPDF::Dictionary] setting default values on wrong classes in certain
|
|
39
|
+
situations
|
|
40
|
+
|
|
41
|
+
|
|
1
42
|
## 0.33.0 - 2023-08-02
|
|
2
43
|
|
|
3
44
|
### Added
|
|
@@ -39,7 +80,7 @@
|
|
|
39
80
|
|
|
40
81
|
### Fixed
|
|
41
82
|
|
|
42
|
-
**Breaking change**: [HexaPDF::Object::make_direct] now needs the document
|
|
83
|
+
* **Breaking change**: [HexaPDF::Object::make_direct] now needs the document
|
|
43
84
|
instance as second argument to correctly resolve references
|
|
44
85
|
* [HexaPDF::Layout::ColumnBox], [HexaPDF::Layout::ListBox] and
|
|
45
86
|
[HexaPDF::Layout::ImageBox] to correctly respond to `#empty?`
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# # Optional Content (a.k.a. Layers)
|
|
2
|
+
#
|
|
3
|
+
# This example shows how to create and assign optional content groups (OCGs) to
|
|
4
|
+
# parts of the content of a page.
|
|
5
|
+
#
|
|
6
|
+
# Four OCGs are created: Squares, Black, Blue, and Orange. The Squares one is
|
|
7
|
+
# applied to everything, the others to the respectively colored squares.
|
|
8
|
+
#
|
|
9
|
+
# When viewed in a compatible viewer, the "Optional Content" or "Layers" panel
|
|
10
|
+
# can be used to switch the layers on and off, resulting in the respective
|
|
11
|
+
# squares appearing or disappearing. Initially, the blue one is not shown, only
|
|
12
|
+
# the black and orange ones.
|
|
13
|
+
#
|
|
14
|
+
# Additionally, if supported by a viewer and if the visibility hasn't been
|
|
15
|
+
# manually changed, the OCGs for the squares are also configured to only be
|
|
16
|
+
# visible at certain zoom levels. For example, the black one is only visible up
|
|
17
|
+
# to a zoom level of 100%.
|
|
18
|
+
#
|
|
19
|
+
# Usage:
|
|
20
|
+
# : `ruby optional_content.rb`
|
|
21
|
+
#
|
|
22
|
+
require 'hexapdf'
|
|
23
|
+
|
|
24
|
+
doc = HexaPDF::Document.new
|
|
25
|
+
|
|
26
|
+
ocg = doc.optional_content.ocg('Squares')
|
|
27
|
+
ocg1 = doc.optional_content.ocg('Black')
|
|
28
|
+
ocg1.zoom(max: 1)
|
|
29
|
+
ocg1.add_to_ui(path: ocg)
|
|
30
|
+
ocg2 = doc.optional_content.ocg('Blue')
|
|
31
|
+
ocg2.zoom(min: 1, max: 2)
|
|
32
|
+
ocg2.add_to_ui(path: ocg)
|
|
33
|
+
ocg2.off!
|
|
34
|
+
ocg3 = doc.optional_content.ocg('Orange')
|
|
35
|
+
ocg3.zoom(min: 2, max: 20)
|
|
36
|
+
ocg3.add_to_ui(path: ocg)
|
|
37
|
+
|
|
38
|
+
canvas = doc.pages.add([0, 0, 200, 200]).canvas
|
|
39
|
+
canvas.optional_content(ocg) do
|
|
40
|
+
canvas.optional_content(ocg1) do
|
|
41
|
+
canvas.fill_color('black').rectangle(20, 80, 100, 100).fill
|
|
42
|
+
end
|
|
43
|
+
canvas.optional_content(ocg2) do
|
|
44
|
+
canvas.fill_color('hp-blue').rectangle(50, 50, 100, 100).fill
|
|
45
|
+
end
|
|
46
|
+
canvas.optional_content(ocg3) do
|
|
47
|
+
canvas.fill_color('hp-orange').rectangle(80, 20, 100, 100).fill
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
doc.optional_content.default_configuration[:AS] = [
|
|
52
|
+
{Event: :View, Category: [:Zoom], OCGs: [ocg1, ocg2, ocg3]}
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
doc.write('optional_content.pdf')
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# # Composer - Optional Content
|
|
2
|
+
#
|
|
3
|
+
# This example shows how to use the optional content feature to create a quiz
|
|
4
|
+
# where the answers can be individually shown and hidden. There is also a link
|
|
5
|
+
# after the questions to toggle all answers.
|
|
6
|
+
#
|
|
7
|
+
# Note: To provide the "All answers" layer switch functionality we need to make
|
|
8
|
+
# use of optional content membership dictionaries. However, this PDF feature is
|
|
9
|
+
# not supported by all PDF viewers. To enable the "All answers" switch in this
|
|
10
|
+
# example, use `a1m`, `a2m`, and `a3m` instead of `a1`, `a2`, and `a3` when
|
|
11
|
+
# defining the optional content for a box.
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# : `ruby composer_optional_content.rb`
|
|
15
|
+
#
|
|
16
|
+
require 'hexapdf'
|
|
17
|
+
|
|
18
|
+
HexaPDF::Composer.create('composer_optional_content.pdf') do |composer|
|
|
19
|
+
composer.style(:question, font_size: 16, margin: [0, 0, 16], fill_color: 'hp-blue')
|
|
20
|
+
composer.style(:answer, font: 'ZapfDingbats', fill_color: "green")
|
|
21
|
+
|
|
22
|
+
all = composer.document.optional_content.ocg('All answers')
|
|
23
|
+
a1 = composer.document.optional_content.ocg('Answer 1')
|
|
24
|
+
a1m = composer.document.optional_content.create_ocmd([a1, all], policy: :any_on)
|
|
25
|
+
a2 = composer.document.optional_content.ocg('Answer 2')
|
|
26
|
+
a2m = composer.document.optional_content.create_ocmd([a2, all], policy: :any_on)
|
|
27
|
+
a3 = composer.document.optional_content.ocg('Answer 3')
|
|
28
|
+
a3m = composer.document.optional_content.create_ocmd([a3, all], policy: :any_on)
|
|
29
|
+
|
|
30
|
+
composer.text('The Great Ruby Quiz', align: :center, margin: [0, 0, 24],
|
|
31
|
+
font: ['Helvetica', variant: :bold], font_size: 24)
|
|
32
|
+
|
|
33
|
+
composer.list(item_type: :decimal, item_spacing: 32, style: :question) do |listing|
|
|
34
|
+
listing.multiple do |item|
|
|
35
|
+
item.text('Who created Ruby?', style: :question)
|
|
36
|
+
item.column(columns: 3, gaps: 5) do |cols|
|
|
37
|
+
cols.list(item_type: :decimal) do |answers|
|
|
38
|
+
answers.text('Guido van Rossum')
|
|
39
|
+
answers.multiple do |answer|
|
|
40
|
+
answer.text('Yukihiro “Matz” Matsumoto', position: :float)
|
|
41
|
+
answer.text("\u{a0}\u{a0}4", style: :answer,
|
|
42
|
+
properties: {'optional_content' => a1})
|
|
43
|
+
end
|
|
44
|
+
answers.text('Rob Pike')
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
listing.multiple do |item|
|
|
50
|
+
item.text('When was Ruby created?', style: :question)
|
|
51
|
+
item.column(columns: 3, gaps: 5) do |cols|
|
|
52
|
+
cols.list(item_type: :decimal) do |answers|
|
|
53
|
+
answers.text('1991')
|
|
54
|
+
answers.text('1992')
|
|
55
|
+
answers.multiple do |answer|
|
|
56
|
+
answer.text('1993', position: :float)
|
|
57
|
+
answer.text("\u{a0}\u{a0}4", style: :answer,
|
|
58
|
+
properties: {'optional_content' => a2})
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
listing.multiple do |item|
|
|
65
|
+
item.text('What is the best PDF library for Ruby?', style: :question)
|
|
66
|
+
answer = composer.document.layout.text('There are several PDF libraries for ' \
|
|
67
|
+
'Ruby but the best is HexaPDF! :)',
|
|
68
|
+
width: 400,
|
|
69
|
+
properties: {'optional_content' => a3})
|
|
70
|
+
item.formatted_text([{box: answer}], border: {width: [0, 0, 1]})
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
action = composer.document.wrap({Type: :Action, S: :SetOCGState})
|
|
75
|
+
action.add_state_change(:toggle, [a1, a2, a3])
|
|
76
|
+
composer.text("Click to toggle answers", border: {width: 1, color: "red"},
|
|
77
|
+
position_hint: :right, padding: 2, overlays: [[:link, action: action]])
|
|
78
|
+
|
|
79
|
+
composer.document.optional_content.default_configuration(
|
|
80
|
+
BaseState: :OFF,
|
|
81
|
+
Order: [all, a1, a2, a3],
|
|
82
|
+
)
|
|
83
|
+
end
|
data/lib/hexapdf/cli/command.rb
CHANGED
|
@@ -53,9 +53,15 @@ module HexaPDF
|
|
|
53
53
|
module Extensions #:nodoc:
|
|
54
54
|
def help_banner #:nodoc:
|
|
55
55
|
"hexapdf #{HexaPDF::VERSION} - Versatile PDF Manipulation Tool\n" \
|
|
56
|
-
"Copyright (c) 2014-
|
|
56
|
+
"Copyright (c) 2014-2023 Thomas Leitner; licensed under the AGPLv3\n\n" \
|
|
57
57
|
"#{format(usage, indent: 7)}\n\n"
|
|
58
58
|
end
|
|
59
|
+
|
|
60
|
+
def help #:nodoc:
|
|
61
|
+
super << format("See https://hexapdf.gettalong.org/documentation/hexapdf.1.html " \
|
|
62
|
+
"for the full manual page with examples.", indent: 0)
|
|
63
|
+
end
|
|
64
|
+
|
|
59
65
|
end
|
|
60
66
|
|
|
61
67
|
include Extensions
|
data/lib/hexapdf/cli/fonts.rb
CHANGED
|
@@ -127,7 +127,7 @@ module HexaPDF
|
|
|
127
127
|
page.resources[:Font]&.each(&font_proc)
|
|
128
128
|
page.resources[:XObject]&.each do |_, xobj|
|
|
129
129
|
next unless xobj[:Subtype] == :Form
|
|
130
|
-
xobj.
|
|
130
|
+
xobj.resources[:Font]&.each(&font_proc)
|
|
131
131
|
end
|
|
132
132
|
page.each_annotation do |annotation|
|
|
133
133
|
appearance = annotation.appearance
|
data/lib/hexapdf/cli/inspect.rb
CHANGED
|
@@ -93,11 +93,9 @@ module HexaPDF
|
|
|
93
93
|
|
|
94
94
|
private
|
|
95
95
|
|
|
96
|
-
# :nodoc:
|
|
97
|
-
COMMAND_LIST = %w[object recursive stream raw-stream xref catalog trailer pages
|
|
96
|
+
COMMAND_LIST = %w[object recursive stream raw-stream xref catalog trailer pages # :nodoc:
|
|
98
97
|
page-count search quit help]
|
|
99
|
-
# :nodoc:
|
|
100
|
-
RELINE_COMPLETION_PROC = proc do |s|
|
|
98
|
+
RELINE_COMPLETION_PROC = proc do |s| # :nodoc:
|
|
101
99
|
if s.empty?
|
|
102
100
|
COMMAND_DESCRIPTIONS.map {|cmd, desc| cmd.ljust(35) << desc }
|
|
103
101
|
else
|
data/lib/hexapdf/composer.rb
CHANGED
|
@@ -401,7 +401,7 @@ module HexaPDF
|
|
|
401
401
|
@document.layout.box_creation_method?(name) || super
|
|
402
402
|
end
|
|
403
403
|
|
|
404
|
-
# Draws the given HexaPDF::Layout::Box.
|
|
404
|
+
# Draws the given HexaPDF::Layout::Box and returns the last drawn box.
|
|
405
405
|
#
|
|
406
406
|
# The box is drawn into the current frame if possible. If it doesn't fit, the box is split. If
|
|
407
407
|
# it still doesn't fit, a new region of the frame is determined and then the process starts
|
|
@@ -433,6 +433,7 @@ module HexaPDF
|
|
|
433
433
|
end
|
|
434
434
|
end
|
|
435
435
|
end
|
|
436
|
+
box
|
|
436
437
|
end
|
|
437
438
|
|
|
438
439
|
# Creates a stamp (Form XObject) which can be used like an image multiple times on a single page
|
|
@@ -268,7 +268,8 @@ module HexaPDF
|
|
|
268
268
|
#
|
|
269
269
|
# The value needs to be an object that responds to \#call(character, font_wrapper) where
|
|
270
270
|
# +character+ is the Unicode character for the missing glyph and returns a substitute glyph to
|
|
271
|
-
# be used instead.
|
|
271
|
+
# be used instead. This substitute glyph needs to be from the same font, i.e. it needs to be
|
|
272
|
+
# created through the provided +font_wrapper+ instance.
|
|
272
273
|
#
|
|
273
274
|
# The +font_wrapper+ argument is the used font wrapper object, e.g.
|
|
274
275
|
# HexaPDF::Font::TrueTypeWrapper. To access the HexaPDF::Document instance from which this hook
|
|
@@ -609,6 +610,23 @@ module HexaPDF
|
|
|
609
610
|
XXOutlineItem: 'HexaPDF::Type::OutlineItem',
|
|
610
611
|
PageLabel: 'HexaPDF::Type::PageLabel',
|
|
611
612
|
XXMarkInformation: 'HexaPDF::Type::MarkInformation',
|
|
613
|
+
OCG: 'HexaPDF::Type::OptionalContentGroup',
|
|
614
|
+
OCMD: 'HexaPDF::Type::OptionalContentMembership',
|
|
615
|
+
XXOCUsage: 'HexaPDF::Type::OptionalContentGroup::OptionalContentUsage',
|
|
616
|
+
XXOCUsageCreatorInfo: 'HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::CreatorInfo',
|
|
617
|
+
XXOCUsageLanguage: 'HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::Language',
|
|
618
|
+
XXOCUsageExport: 'HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::Export',
|
|
619
|
+
XXOCUsageZoom: 'HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::Zoom',
|
|
620
|
+
XXOCUsagePrint: 'HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::Print',
|
|
621
|
+
XXOCUsageView: 'HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::View',
|
|
622
|
+
XXOCUsageUser: 'HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::User',
|
|
623
|
+
XXOCUsagePageElement: 'HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::PageElement',
|
|
624
|
+
XXOCProperties: 'HexaPDF::Type::OptionalContentProperties',
|
|
625
|
+
XXOCConfiguration: 'HexaPDF::Type::OptionalContentConfiguration',
|
|
626
|
+
XXOCUsageApplication: 'HexaPDF::Type::OptionalContentConfiguration::UsageApplication',
|
|
627
|
+
XXReference: 'HexaPDF::Type::Form::Reference',
|
|
628
|
+
XXCIDSystemInfo: 'HexaPDF::Type::CIDFont::CIDSystemInfo',
|
|
629
|
+
Group: 'HexaPDF::Type::Form::Group',
|
|
612
630
|
},
|
|
613
631
|
'object.subtype_map' => {
|
|
614
632
|
nil => {
|
|
@@ -623,6 +641,7 @@ module HexaPDF
|
|
|
623
641
|
GoToR: 'HexaPDF::Type::Actions::GoToR',
|
|
624
642
|
Launch: 'HexaPDF::Type::Actions::Launch',
|
|
625
643
|
URI: 'HexaPDF::Type::Actions::URI',
|
|
644
|
+
SetOCGState: 'HexaPDF::Type::Actions::SetOCGState',
|
|
626
645
|
Text: 'HexaPDF::Type::Annotations::Text',
|
|
627
646
|
Link: 'HexaPDF::Type::Annotations::Link',
|
|
628
647
|
Widget: 'HexaPDF::Type::Annotations::Widget',
|
|
@@ -644,6 +663,7 @@ module HexaPDF
|
|
|
644
663
|
GoToR: 'HexaPDF::Type::Actions::GoToR',
|
|
645
664
|
Launch: 'HexaPDF::Type::Actions::Launch',
|
|
646
665
|
URI: 'HexaPDF::Type::Actions::URI',
|
|
666
|
+
SetOCGState: 'HexaPDF::Type::Actions::SetOCGState',
|
|
647
667
|
},
|
|
648
668
|
Annot: {
|
|
649
669
|
Text: 'HexaPDF::Type::Annotations::Text',
|
|
@@ -317,6 +317,14 @@ module HexaPDF
|
|
|
317
317
|
@context.resources
|
|
318
318
|
end
|
|
319
319
|
|
|
320
|
+
# Returns the position (x,y) transformed by the current transformation matrix.
|
|
321
|
+
#
|
|
322
|
+
# The resulting position should be interpreted in terms of the coordinate system of the
|
|
323
|
+
# context object (e.g. the page or Form XObject).
|
|
324
|
+
def pos(x, y)
|
|
325
|
+
graphics_state.ctm.evaluate(x, y)
|
|
326
|
+
end
|
|
327
|
+
|
|
320
328
|
# :call-seq:
|
|
321
329
|
# canvas.save_graphics_state => canvas
|
|
322
330
|
# canvas.save_graphics_state { block } => canvas
|
|
@@ -2483,6 +2491,50 @@ module HexaPDF
|
|
|
2483
2491
|
self
|
|
2484
2492
|
end
|
|
2485
2493
|
|
|
2494
|
+
# :call-seq:
|
|
2495
|
+
# canvas.optional_content(ocg, &block) -> canvas
|
|
2496
|
+
# canvas.optional_content(name, use_existing_ocg: true, &block) -> canvas
|
|
2497
|
+
#
|
|
2498
|
+
# Inserts an optional content sequence. Returns +self+.
|
|
2499
|
+
#
|
|
2500
|
+
# An optional content sequence marks part of the content stream as belonging to the given
|
|
2501
|
+
# optional content group. See HexaPDF::Type::OptionalContentProperties for details.
|
|
2502
|
+
#
|
|
2503
|
+
# If the first argument is already an optional content group dictionary, it is used.
|
|
2504
|
+
# Otherwise, the first argument needs to be the name of the optional content group. In that
|
|
2505
|
+
# case, the +use_existing_ocg+ specifies whether the first found optional content group with
|
|
2506
|
+
# that name should be used or whether a new OCG should always be created.
|
|
2507
|
+
#
|
|
2508
|
+
# If invoked without a block, a corresponding call to #end_optional_content must be done.
|
|
2509
|
+
# Otherwise the optional content sequence automatically ends when the block is finished.
|
|
2510
|
+
#
|
|
2511
|
+
# Examples:
|
|
2512
|
+
#
|
|
2513
|
+
# canvas.optional_content('Hints')
|
|
2514
|
+
# # Other instructions
|
|
2515
|
+
# canvas.end_optional_content
|
|
2516
|
+
#
|
|
2517
|
+
# canvas.optional_content('Hints', use_existing_ocg: false) do
|
|
2518
|
+
# # Other instructions
|
|
2519
|
+
# end
|
|
2520
|
+
#
|
|
2521
|
+
# See: PDF2.0 s8.11, #end_optional_content, HexaPDF::Type::OptionalContentProperties
|
|
2522
|
+
def optional_content(ocg, use_existing_ocg: true, &block)
|
|
2523
|
+
ocg = if ocg.kind_of?(HexaPDF::Dictionary) || !use_existing_ocg
|
|
2524
|
+
context.document.optional_content.add_ocg(ocg)
|
|
2525
|
+
else
|
|
2526
|
+
context.document.optional_content.ocg(ocg, create: true)
|
|
2527
|
+
end
|
|
2528
|
+
marked_content_sequence(:OC, property_list: ocg, &block)
|
|
2529
|
+
end
|
|
2530
|
+
|
|
2531
|
+
# Ends an optional content sequence and returns +self+.
|
|
2532
|
+
#
|
|
2533
|
+
# See #optional_content for details.
|
|
2534
|
+
#
|
|
2535
|
+
# See: PDF2.0 s8.11
|
|
2536
|
+
alias :end_optional_content :end_marked_content_sequence
|
|
2537
|
+
|
|
2486
2538
|
# Creates and returns a color object from the given color specification. See #stroke_color for
|
|
2487
2539
|
# details on the possible color specifications.
|
|
2488
2540
|
#
|
|
@@ -1001,6 +1001,8 @@ module HexaPDF
|
|
|
1001
1001
|
|
|
1002
1002
|
# Mapping of operator names to their default operator implementations.
|
|
1003
1003
|
DEFAULT_OPERATORS = {
|
|
1004
|
+
BX: NoArgumentOperator.new('BX'),
|
|
1005
|
+
EX: NoArgumentOperator.new('EX'),
|
|
1004
1006
|
q: SaveGraphicsState.new,
|
|
1005
1007
|
Q: RestoreGraphicsState.new,
|
|
1006
1008
|
cm: ConcatenateMatrix.new,
|
data/lib/hexapdf/dictionary.rb
CHANGED
|
@@ -249,6 +249,7 @@ module HexaPDF
|
|
|
249
249
|
# Sets all required fields that have no current value but a default value to their respective
|
|
250
250
|
# default value.
|
|
251
251
|
def set_required_fields_with_defaults
|
|
252
|
+
return if (type = value[:Type]) && self.class.type != type
|
|
252
253
|
self.class.each_field do |name, field|
|
|
253
254
|
if !key?(name) && field.required? && field.default?
|
|
254
255
|
value[name] = field.default
|
|
@@ -313,8 +313,7 @@ module HexaPDF
|
|
|
313
313
|
[String, Time, Date, DateTime]
|
|
314
314
|
end
|
|
315
315
|
|
|
316
|
-
# :nodoc:
|
|
317
|
-
DATE_RE = /\AD:(\d{4})(\d\d)?(\d\d)?(\d\d)?(\d\d)?(\d\d)?([Z+-])?(?:(\d+)(?:'|'(\d+)'?|\z)?)?\z/n
|
|
316
|
+
DATE_RE = /\AD:(\d{4})(\d\d)?(\d\d)?(\d\d)?(\d\d)?(\d\d)?([Z+-])?(?:(\d+)(?:'|'(\d+)'?|\z)?)?\z/n # :nodoc:
|
|
318
317
|
|
|
319
318
|
# Checks if the given object is a string and converts into a Time object if possible.
|
|
320
319
|
# Otherwise returns +nil+.
|
|
@@ -40,8 +40,7 @@ module HexaPDF
|
|
|
40
40
|
# Holds the result of verifying a signature.
|
|
41
41
|
class VerificationResult
|
|
42
42
|
|
|
43
|
-
# :nodoc:
|
|
44
|
-
MESSAGE_SORT_MAP = {
|
|
43
|
+
MESSAGE_SORT_MAP = { # :nodoc:
|
|
45
44
|
info: {warning: 1, error: 1, info: 0},
|
|
46
45
|
warning: {info: -1, error: 1, warning: 0},
|
|
47
46
|
error: {info: -1, warning: -1, error: 0},
|
|
@@ -607,6 +607,9 @@ module HexaPDF
|
|
|
607
607
|
# Finally, a default font is set if necessary to ensure that the style object works in all
|
|
608
608
|
# cases.
|
|
609
609
|
def retrieve_style(style, properties = nil)
|
|
610
|
+
if style.kind_of?(Symbol) && !@styles.key?(style)
|
|
611
|
+
raise HexaPDF::Error, "Style #{style} not defined"
|
|
612
|
+
end
|
|
610
613
|
style = HexaPDF::Layout::Style.create(@styles[style] || style || @styles[:base])
|
|
611
614
|
style = style.dup.update(**properties) unless properties.nil? || properties.empty?
|
|
612
615
|
style.font('Times') unless style.font?
|
|
@@ -246,7 +246,7 @@ module HexaPDF
|
|
|
246
246
|
|
|
247
247
|
labels = @document.catalog.page_labels(create: true)
|
|
248
248
|
labels.add_entry(start_index, page_label)
|
|
249
|
-
labels.add_entry(0, {S: :
|
|
249
|
+
labels.add_entry(0, {S: :D}) unless labels.find_entry(0)
|
|
250
250
|
|
|
251
251
|
page_label
|
|
252
252
|
end
|
data/lib/hexapdf/document.rb
CHANGED
|
@@ -538,6 +538,13 @@ module HexaPDF
|
|
|
538
538
|
catalog.outline
|
|
539
539
|
end
|
|
540
540
|
|
|
541
|
+
# Returns the main object for working with optional content (a.k.a. layers).
|
|
542
|
+
#
|
|
543
|
+
# See: Type::Catalog#optional_content
|
|
544
|
+
def optional_content
|
|
545
|
+
catalog.optional_content
|
|
546
|
+
end
|
|
547
|
+
|
|
541
548
|
# Executes the given task and returns its result.
|
|
542
549
|
#
|
|
543
550
|
# Tasks provide an extensible way for performing operations on a PDF document without
|
|
@@ -92,9 +92,8 @@ module HexaPDF
|
|
|
92
92
|
|
|
93
93
|
private
|
|
94
94
|
|
|
95
|
-
# :nodoc:
|
|
96
95
|
# Rijndael S-box
|
|
97
|
-
SBOX = [
|
|
96
|
+
SBOX = [ # :nodoc:
|
|
98
97
|
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
|
99
98
|
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
|
100
99
|
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
|
@@ -113,9 +112,8 @@ module HexaPDF
|
|
|
113
112
|
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
|
114
113
|
].freeze
|
|
115
114
|
|
|
116
|
-
# :nodoc:
|
|
117
115
|
# Inverse of the Rijndael S-box
|
|
118
|
-
INV_SBOX = [
|
|
116
|
+
INV_SBOX = [ # :nodoc:
|
|
119
117
|
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
|
120
118
|
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
|
121
119
|
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
|
@@ -134,12 +132,10 @@ module HexaPDF
|
|
|
134
132
|
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
|
135
133
|
].freeze
|
|
136
134
|
|
|
137
|
-
# :nodoc:
|
|
138
|
-
RCON = [0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c].freeze
|
|
135
|
+
RCON = [0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c].freeze # :nodoc:
|
|
139
136
|
|
|
140
|
-
# :nodoc:
|
|
141
137
|
# Precomputed Galois multiplication table for multiplication with 2 in GF(2^8)
|
|
142
|
-
G2MULT = [
|
|
138
|
+
G2MULT = [ # :nodoc:
|
|
143
139
|
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
|
|
144
140
|
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
|
|
145
141
|
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
|
|
@@ -158,9 +154,8 @@ module HexaPDF
|
|
|
158
154
|
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
|
|
159
155
|
].freeze
|
|
160
156
|
|
|
161
|
-
# :nodoc:
|
|
162
157
|
# Precomputed Galois multiplication table for multiplication with 3 in GF(2^8)
|
|
163
|
-
G3MULT = [
|
|
158
|
+
G3MULT = [ # :nodoc:
|
|
164
159
|
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
|
|
165
160
|
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
|
|
166
161
|
0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
|
|
@@ -179,9 +174,8 @@ module HexaPDF
|
|
|
179
174
|
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
|
|
180
175
|
].freeze
|
|
181
176
|
|
|
182
|
-
# :nodoc:
|
|
183
177
|
# Precomputed Galois multiplication table for multiplication with 9 in GF(2^8)
|
|
184
|
-
G9MULT = [
|
|
178
|
+
G9MULT = [ # :nodoc:
|
|
185
179
|
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
|
|
186
180
|
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
|
|
187
181
|
0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
|
|
@@ -200,9 +194,8 @@ module HexaPDF
|
|
|
200
194
|
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
|
|
201
195
|
].freeze
|
|
202
196
|
|
|
203
|
-
# :nodoc:
|
|
204
197
|
# Precomputed Galois multiplication table for multiplication with 11 in GF(2^8)
|
|
205
|
-
G11MULT = [
|
|
198
|
+
G11MULT = [ # :nodoc:
|
|
206
199
|
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
|
|
207
200
|
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
|
|
208
201
|
0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
|
|
@@ -221,9 +214,8 @@ module HexaPDF
|
|
|
221
214
|
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
|
|
222
215
|
].freeze
|
|
223
216
|
|
|
224
|
-
# :nodoc:
|
|
225
217
|
# Precomputed Galois multiplication table for multiplication with 13 in GF(2^8)
|
|
226
|
-
G13MULT = [
|
|
218
|
+
G13MULT = [ # :nodoc:
|
|
227
219
|
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
|
|
228
220
|
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
|
|
229
221
|
0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
|
|
@@ -242,9 +234,8 @@ module HexaPDF
|
|
|
242
234
|
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
|
|
243
235
|
].freeze
|
|
244
236
|
|
|
245
|
-
# :nodoc:
|
|
246
237
|
# Precomputed Galois multiplication table for multiplication with 14 in GF(2^8)
|
|
247
|
-
G14MULT = [
|
|
238
|
+
G14MULT = [ # :nodoc:
|
|
248
239
|
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
|
|
249
240
|
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
|
|
250
241
|
0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
|
|
@@ -263,9 +254,8 @@ module HexaPDF
|
|
|
263
254
|
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
|
|
264
255
|
].freeze
|
|
265
256
|
|
|
266
|
-
# :nodoc:
|
|
267
257
|
# Number of rounds needed in various parts of the algorithm, depends on the key size
|
|
268
|
-
NUMBER_OF_ROUNDS = {16 => 10, 24 => 12, 32 => 14}.freeze
|
|
258
|
+
NUMBER_OF_ROUNDS = {16 => 10, 24 => 12, 32 => 14}.freeze # :nodoc:
|
|
269
259
|
|
|
270
260
|
# KeyExpansion step
|
|
271
261
|
#
|
data/lib/hexapdf/layout/box.rb
CHANGED
|
@@ -127,10 +127,24 @@ module HexaPDF
|
|
|
127
127
|
#
|
|
128
128
|
# This can be used to store arbitrary information on boxes for later use. For example, a
|
|
129
129
|
# generic style layer could use one or more custom properties for its work.
|
|
130
|
+
#
|
|
131
|
+
# The Box class itself uses the following properties:
|
|
132
|
+
#
|
|
133
|
+
# optional_content::
|
|
134
|
+
#
|
|
135
|
+
# If this property is set, it needs to be an optional content group dictionary, a String
|
|
136
|
+
# defining an (optionally existing) optional content group dictionary, or an optional
|
|
137
|
+
# content membership dictionary.
|
|
138
|
+
#
|
|
139
|
+
# The whole content of the box, i.e. including padding, border, background..., is
|
|
140
|
+
# wrapped with the appropriate commands so that the optional content group or membership
|
|
141
|
+
# dictionary specifies whether the content is shown or not.
|
|
142
|
+
#
|
|
143
|
+
# See: HexaPDF::Type::OptionalContentProperties
|
|
130
144
|
attr_reader :properties
|
|
131
145
|
|
|
132
146
|
# :call-seq:
|
|
133
|
-
# Box.new(width: 0, height: 0, style: nil, properties:
|
|
147
|
+
# Box.new(width: 0, height: 0, style: nil, properties: nil) {|canv, box| block} -> box
|
|
134
148
|
#
|
|
135
149
|
# Creates a new Box object with the given width and height that uses the provided block when
|
|
136
150
|
# it is asked to draw itself on a canvas (see #draw).
|
|
@@ -138,11 +152,11 @@ module HexaPDF
|
|
|
138
152
|
# Since the final location of the box is not known beforehand, the drawing operations inside
|
|
139
153
|
# the block should draw inside the rectangle (0, 0, content_width, content_height) - note that
|
|
140
154
|
# the width and height of the box may not be known beforehand.
|
|
141
|
-
def initialize(width: 0, height: 0, style: nil, properties:
|
|
155
|
+
def initialize(width: 0, height: 0, style: nil, properties: nil, &block)
|
|
142
156
|
@width = @initial_width = width
|
|
143
157
|
@height = @initial_height = height
|
|
144
158
|
@style = Style.create(style)
|
|
145
|
-
@properties = properties
|
|
159
|
+
@properties = properties || {}
|
|
146
160
|
@draw_block = block
|
|
147
161
|
@fit_successful = false
|
|
148
162
|
@split_box = false
|
|
@@ -220,6 +234,10 @@ module HexaPDF
|
|
|
220
234
|
# instance variable to +nil+ or a valid block. This is useful to avoid unnecessary set-up
|
|
221
235
|
# operations when the block does nothing.
|
|
222
236
|
def draw(canvas, x, y)
|
|
237
|
+
if (oc = properties['optional_content'])
|
|
238
|
+
canvas.optional_content(oc)
|
|
239
|
+
end
|
|
240
|
+
|
|
223
241
|
if style.background_color? && style.background_color
|
|
224
242
|
canvas.save_graphics_state do
|
|
225
243
|
canvas.opacity(fill_alpha: style.background_alpha).
|
|
@@ -233,6 +251,8 @@ module HexaPDF
|
|
|
233
251
|
draw_content(canvas, x + reserved_width_left, y + reserved_height_bottom)
|
|
234
252
|
|
|
235
253
|
style.overlays.draw(canvas, x, y, self) if style.overlays?
|
|
254
|
+
|
|
255
|
+
canvas.end_optional_content if oc
|
|
236
256
|
end
|
|
237
257
|
|
|
238
258
|
# Returns +true+ if no drawing operations are performed.
|
|
@@ -177,7 +177,8 @@ module HexaPDF
|
|
|
177
177
|
[column_left, column_bottom + height])
|
|
178
178
|
shape = Geom2D::Algorithms::PolygonOperation.run(frame.shape, rect, :intersection)
|
|
179
179
|
end
|
|
180
|
-
column_frame = Frame.new(column_left, column_bottom, column_width, height,
|
|
180
|
+
column_frame = Frame.new(column_left, column_bottom, column_width, height,
|
|
181
|
+
shape: shape, context: frame.context)
|
|
181
182
|
@box_fitter << column_frame
|
|
182
183
|
end
|
|
183
184
|
|