hexapdf 0.43.0 → 0.45.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 +36 -0
- data/examples/027-composer_optional_content.rb +6 -4
- data/examples/030-pdfa.rb +13 -11
- data/lib/hexapdf/composer.rb +23 -0
- data/lib/hexapdf/content/canvas.rb +3 -3
- data/lib/hexapdf/content/canvas_composer.rb +1 -0
- data/lib/hexapdf/document/files.rb +7 -2
- data/lib/hexapdf/document/layout.rb +15 -3
- data/lib/hexapdf/document/metadata.rb +12 -1
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/layout/box.rb +180 -66
- data/lib/hexapdf/layout/box_fitter.rb +1 -0
- data/lib/hexapdf/layout/column_box.rb +18 -28
- data/lib/hexapdf/layout/container_box.rb +6 -6
- data/lib/hexapdf/layout/frame.rb +13 -94
- data/lib/hexapdf/layout/image_box.rb +4 -4
- data/lib/hexapdf/layout/list_box.rb +13 -31
- data/lib/hexapdf/layout/style.rb +8 -4
- data/lib/hexapdf/layout/table_box.rb +55 -58
- data/lib/hexapdf/layout/text_box.rb +84 -71
- data/lib/hexapdf/layout/text_fragment.rb +1 -1
- data/lib/hexapdf/layout/text_layouter.rb +7 -8
- data/lib/hexapdf/parser.rb +5 -2
- data/lib/hexapdf/rectangle.rb +4 -4
- data/lib/hexapdf/type/file_specification.rb +9 -5
- data/lib/hexapdf/type/form.rb +2 -2
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/content/test_canvas_composer.rb +13 -8
- data/test/hexapdf/document/test_files.rb +5 -0
- data/test/hexapdf/document/test_layout.rb +16 -0
- data/test/hexapdf/document/test_metadata.rb +21 -0
- data/test/hexapdf/layout/test_box.rb +93 -37
- data/test/hexapdf/layout/test_box_fitter.rb +7 -0
- data/test/hexapdf/layout/test_column_box.rb +7 -13
- data/test/hexapdf/layout/test_container_box.rb +1 -1
- data/test/hexapdf/layout/test_frame.rb +7 -46
- data/test/hexapdf/layout/test_image_box.rb +14 -6
- data/test/hexapdf/layout/test_list_box.rb +26 -27
- data/test/hexapdf/layout/test_table_box.rb +47 -54
- data/test/hexapdf/layout/test_text_box.rb +83 -83
- data/test/hexapdf/test_composer.rb +20 -5
- data/test/hexapdf/test_parser.rb +8 -0
- data/test/hexapdf/test_serializer.rb +1 -0
- data/test/hexapdf/type/test_file_specification.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd31e769d2a906198da2a4194085cb2a884fa3879442b75add168d7f81d67d8b
|
4
|
+
data.tar.gz: 43c2b4ba4df2f997d470835995f2581aa306c639c63ddc892e648d94605f3b22
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f17a303dba8104974564a213c72c0f0862c520964a3255b575544489ccb5a17a468d093d3970817903c4eb798e888592410db18447d3264d535f3a01a4a94c82
|
7
|
+
data.tar.gz: d5727e2f2bfb5ed827ac92eecc8cd9e0ba73044150ba07d03623dccde43dc29db1cddc2fbce24bfd63268522e7965519e188271c2bc9c00162b1a660fc468b74
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,39 @@
|
|
1
|
+
## 0.45.0 - 2024-06-18
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* [HexaPDF::Document::Layout#styles] and [HexaPDF::Composer#styles] for defining
|
6
|
+
multiple styles at once
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
|
10
|
+
* [HexaPDF::Layout::Box#fit] to set width/height correctly for boxes with
|
11
|
+
position `:flow`
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
|
15
|
+
* Regression in [HexaPDF::Layout::ListBox] that leads to missing markers
|
16
|
+
* [HexaPDF::Content::CanvasComposer#draw_box] to handle truncated boxes
|
17
|
+
* [HexaPDF::Layout::TableBox::Cell] to handle too-big content in all cases
|
18
|
+
|
19
|
+
|
20
|
+
## 0.44.0 - 2024-06-05
|
21
|
+
|
22
|
+
### Added
|
23
|
+
|
24
|
+
* Support for specifying the MIME type when embedding files
|
25
|
+
* Support for adding custom XMP metadata
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
|
29
|
+
* **Breaking change**: Refactored the box implementation of the document layout
|
30
|
+
system
|
31
|
+
|
32
|
+
### Fixed
|
33
|
+
|
34
|
+
* Parsing of invalid files with garbage bytes at the end
|
35
|
+
|
36
|
+
|
1
37
|
## 0.43.0 - 2024-05-26
|
2
38
|
|
3
39
|
### Added
|
@@ -16,8 +16,10 @@
|
|
16
16
|
require 'hexapdf'
|
17
17
|
|
18
18
|
HexaPDF::Composer.create('composer_optional_content.pdf') do |composer|
|
19
|
-
composer.
|
20
|
-
|
19
|
+
composer.styles(
|
20
|
+
question: {font_size: 16, margin: [0, 0, 16], fill_color: 'hp-blue'},
|
21
|
+
answer: {font: 'ZapfDingbats', fill_color: "green"},
|
22
|
+
)
|
21
23
|
|
22
24
|
all = composer.document.optional_content.ocg('All answers')
|
23
25
|
a1 = composer.document.optional_content.ocg('Answer 1')
|
@@ -38,7 +40,7 @@ HexaPDF::Composer.create('composer_optional_content.pdf') do |composer|
|
|
38
40
|
answers.text('Guido van Rossum')
|
39
41
|
answers.multiple do |answer|
|
40
42
|
answer.text('Yukihiro “Matz” Matsumoto', position: :float)
|
41
|
-
answer.text("\u{a0}\u{a0}
|
43
|
+
answer.text("\u{a0}\u{a0}✔", style: :answer,
|
42
44
|
properties: {'optional_content' => a1})
|
43
45
|
end
|
44
46
|
answers.text('Rob Pike')
|
@@ -54,7 +56,7 @@ HexaPDF::Composer.create('composer_optional_content.pdf') do |composer|
|
|
54
56
|
answers.text('1992')
|
55
57
|
answers.multiple do |answer|
|
56
58
|
answer.text('1993', position: :float)
|
57
|
-
answer.text("\u{a0}\u{a0}
|
59
|
+
answer.text("\u{a0}\u{a0}✔", style: :answer,
|
58
60
|
properties: {'optional_content' => a2})
|
59
61
|
end
|
60
62
|
end
|
data/examples/030-pdfa.rb
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
# Usage:
|
9
9
|
# : `ruby pdfa.rb`
|
10
10
|
#
|
11
|
+
|
11
12
|
require 'hexapdf'
|
12
13
|
|
13
14
|
HexaPDF::Composer.create('pdfa.pdf') do |composer|
|
@@ -27,17 +28,18 @@ HexaPDF::Composer.create('pdfa.pdf') do |composer|
|
|
27
28
|
}
|
28
29
|
|
29
30
|
# Define all styles
|
30
|
-
composer.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
31
|
+
composer.styles(
|
32
|
+
base: {font: 'Lato', font_size: 10, line_spacing: 1.3},
|
33
|
+
top: {font_size: 8},
|
34
|
+
top_box: {padding: [100, 0, 0], margin: [0, 0, 10], border: {width: [0, 0, 1]}},
|
35
|
+
header: {font: 'Lato bold', font_size: 20, margin: [50, 0, 20]},
|
36
|
+
line_items: {border: {width: 1, color: "eee"}, margin: [20, 0]},
|
37
|
+
line_item_cell: {font_size: 8},
|
38
|
+
footer: {border: {width: [1, 0, 0], color: "darkgrey"}, padding: [5, 0, 0],
|
39
|
+
valign: :bottom},
|
40
|
+
footer_heading: {font: 'Lato bold', font_size: 8, padding: [0, 0, 8]},
|
41
|
+
footer_text: {font_size: 8, fill_color: "darkgrey"},
|
42
|
+
)
|
41
43
|
|
42
44
|
# Top part
|
43
45
|
composer.box(:container, style: :top_box) do |container|
|
data/lib/hexapdf/composer.rb
CHANGED
@@ -254,6 +254,28 @@ module HexaPDF
|
|
254
254
|
@document.layout.style(name, base: base, **properties)
|
255
255
|
end
|
256
256
|
|
257
|
+
# :call-seq:
|
258
|
+
# composer.styles -> styles
|
259
|
+
# composer.styles(**mapping) -> styles
|
260
|
+
#
|
261
|
+
# Creates multiple named styles at once if +mapping+ is provided, and returns the style mapping.
|
262
|
+
#
|
263
|
+
# See HexaPDF::Document::Layout#styles for details; this method is just a thin wrapper around
|
264
|
+
# that method.
|
265
|
+
#
|
266
|
+
# Example:
|
267
|
+
#
|
268
|
+
# composer.styles(
|
269
|
+
# base: {font_size: 12, leading: 1.2},
|
270
|
+
# header: {font: 'Helvetica', fill_color: "008"},
|
271
|
+
# header1: {base: :header, font_size: 30}
|
272
|
+
# )
|
273
|
+
#
|
274
|
+
# See: HexaPDF::Layout::Style
|
275
|
+
def styles(**mapping)
|
276
|
+
@document.layout.styles(**mapping)
|
277
|
+
end
|
278
|
+
|
257
279
|
# :call-seq:
|
258
280
|
# composer.page_style(name) -> page_style
|
259
281
|
# composer.page_style(name, **attributes, &template_block) -> page_style
|
@@ -425,6 +447,7 @@ module HexaPDF
|
|
425
447
|
if draw_box
|
426
448
|
@frame.draw(@canvas, result)
|
427
449
|
drawn_on_page = true
|
450
|
+
(box = draw_box; break) unless box
|
428
451
|
elsif !@frame.find_next_region
|
429
452
|
unless drawn_on_page
|
430
453
|
raise HexaPDF::Error, "Box doesn't fit on empty page"
|
@@ -1127,7 +1127,7 @@ module HexaPDF
|
|
1127
1127
|
# canvas.rectangle(x, y, width, height, radius: 0) => canvas
|
1128
1128
|
#
|
1129
1129
|
# Appends a rectangle to the current path as a complete subpath (drawn in counterclockwise
|
1130
|
-
# direction), with the bottom
|
1130
|
+
# direction), with the bottom-left corner specified by +x+ and +y+ and the given +width+ and
|
1131
1131
|
# +height+. Returns +self+.
|
1132
1132
|
#
|
1133
1133
|
# If +radius+ is greater than 0, the corners are rounded with the given radius.
|
@@ -1137,7 +1137,7 @@ module HexaPDF
|
|
1137
1137
|
#
|
1138
1138
|
# If there is no current path when the method is invoked, a new path is automatically begun.
|
1139
1139
|
#
|
1140
|
-
# The current point is set to the bottom
|
1140
|
+
# The current point is set to the bottom-left corner if +radius+ is zero, otherwise it is set
|
1141
1141
|
# to (x, y + radius).
|
1142
1142
|
#
|
1143
1143
|
# Examples:
|
@@ -1720,7 +1720,7 @@ module HexaPDF
|
|
1720
1720
|
# If the filename or the IO specifies a PDF file, the first page of this file is used to
|
1721
1721
|
# create a form XObject which is then drawn.
|
1722
1722
|
#
|
1723
|
-
# The +at+ argument has to be an array containing two numbers specifying the bottom
|
1723
|
+
# The +at+ argument has to be an array containing two numbers specifying the bottom-left
|
1724
1724
|
# corner at which to draw the XObject.
|
1725
1725
|
#
|
1726
1726
|
# If +width+ and +height+ are specified, the drawn XObject will have exactly these
|
@@ -96,6 +96,7 @@ module HexaPDF
|
|
96
96
|
draw_box, box = @frame.split(result)
|
97
97
|
if draw_box
|
98
98
|
@frame.draw(@canvas, result)
|
99
|
+
(box = draw_box; break) unless box
|
99
100
|
elsif !@frame.find_next_region
|
100
101
|
raise HexaPDF::Error, "Frame for canvas composer is full and box doesn't fit anymore"
|
101
102
|
end
|
@@ -70,6 +70,9 @@ module HexaPDF
|
|
70
70
|
# description::
|
71
71
|
# A description of the file.
|
72
72
|
#
|
73
|
+
# mime_type::
|
74
|
+
# The MIME type that should be set for embedded files (so only used if +embed+ is +true+).
|
75
|
+
#
|
73
76
|
# embed::
|
74
77
|
# When an IO object is given, it is always embedded and this option is ignored.
|
75
78
|
#
|
@@ -77,7 +80,7 @@ module HexaPDF
|
|
77
80
|
# only a reference to it is stored.
|
78
81
|
#
|
79
82
|
# See: HexaPDF::Type::FileSpecification
|
80
|
-
def add(file_or_io, name: nil, description: nil, embed: true)
|
83
|
+
def add(file_or_io, name: nil, description: nil, mime_type: nil, embed: true)
|
81
84
|
name ||= File.basename(file_or_io) if file_or_io.kind_of?(String)
|
82
85
|
if name.nil?
|
83
86
|
raise ArgumentError, "The name argument is mandatory when given an IO object"
|
@@ -86,7 +89,9 @@ module HexaPDF
|
|
86
89
|
spec = @document.add({Type: :Filespec})
|
87
90
|
spec.path = name
|
88
91
|
spec[:Desc] = description if description
|
89
|
-
|
92
|
+
if embed || !file_or_io.kind_of?(String)
|
93
|
+
spec.embed(file_or_io, name: name, mime_type: mime_type, register: true)
|
94
|
+
end
|
90
95
|
spec
|
91
96
|
end
|
92
97
|
|
@@ -175,9 +175,6 @@ module HexaPDF
|
|
175
175
|
|
176
176
|
end
|
177
177
|
|
178
|
-
# The mapping of style name (a Symbol) to Layout::Style instance.
|
179
|
-
attr_reader :styles
|
180
|
-
|
181
178
|
# Creates a new Layout object for the given PDF document.
|
182
179
|
def initialize(document)
|
183
180
|
@document = document
|
@@ -219,6 +216,21 @@ module HexaPDF
|
|
219
216
|
style
|
220
217
|
end
|
221
218
|
|
219
|
+
# :call-seq:
|
220
|
+
# layout.styles -> styles
|
221
|
+
# layout.styles(**mapping) -> styles
|
222
|
+
#
|
223
|
+
# Returns the mapping of style names to Layout::Style instances. If +mapping+ is provided,
|
224
|
+
# also defines the given styles using #style.
|
225
|
+
#
|
226
|
+
# The argument +mapping+ needs to be a hash mapping a style name (a Symbol) to style
|
227
|
+
# properties. The special key +:base+ can be used to define the base style. For details see
|
228
|
+
# #style.
|
229
|
+
def styles(**mapping)
|
230
|
+
mapping.each {|name, properties| style(name, **properties) } unless mapping.empty?
|
231
|
+
@styles
|
232
|
+
end
|
233
|
+
|
222
234
|
# Creates an inline box for use together with text fragments.
|
223
235
|
#
|
224
236
|
# The +valign+ argument ist used to specify the vertical alignment of the box within the text
|
@@ -161,6 +161,7 @@ module HexaPDF
|
|
161
161
|
@properties = PREDEFINED_PROPERTIES.transform_values(&:dup)
|
162
162
|
@default_language = document.catalog[:Lang] || 'x-default'
|
163
163
|
@metadata = Hash.new {|h, k| h[k] = {} }
|
164
|
+
@custom_metadata = []
|
164
165
|
write_info_dict(true)
|
165
166
|
write_metadata_stream(true)
|
166
167
|
@document.register_listener(:complete_objects, &method(:write_metadata))
|
@@ -248,6 +249,16 @@ module HexaPDF
|
|
248
249
|
end
|
249
250
|
end
|
250
251
|
|
252
|
+
# Adds the given +data+ string as custom metadata to the XMP document.
|
253
|
+
#
|
254
|
+
# The +data+ string must contain a fully valid 'rdf:Description' element.
|
255
|
+
#
|
256
|
+
# Using this method allows adding metadata like PDF/A schema definitions for which there is no
|
257
|
+
# direct support by HexaPDF.
|
258
|
+
def custom_metadata(data)
|
259
|
+
@custom_metadata << data
|
260
|
+
end
|
261
|
+
|
251
262
|
# :call-seq:
|
252
263
|
# metadata.delete
|
253
264
|
# metadata.delete(ns_prefix)
|
@@ -469,7 +480,7 @@ module HexaPDF
|
|
469
480
|
<?xpacket begin="\u{FEFF}" id="#{SecureRandom.uuid.tr('-', '')}"?>
|
470
481
|
<x:xmpmeta xmlns:x="adobe:ns:meta/">
|
471
482
|
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
472
|
-
#{data}
|
483
|
+
#{data}#{@custom_metadata.empty? ? '' : "\n#{@custom_metadata.join("\n")}"}
|
473
484
|
</rdf:RDF>
|
474
485
|
</x:xmpmeta>
|
475
486
|
<?xpacket end="r"?>
|
@@ -51,7 +51,7 @@ module HexaPDF
|
|
51
51
|
attr_accessor :name
|
52
52
|
|
53
53
|
# Character bounding box as array of four numbers, specifying the x- and y-coordinates of
|
54
|
-
# the bottom
|
54
|
+
# the bottom-left corner and the x- and y-coordinates of the top-right corner.
|
55
55
|
attr_accessor :bbox
|
56
56
|
|
57
57
|
end
|
@@ -63,7 +63,7 @@ module HexaPDF
|
|
63
63
|
attr_accessor :weight
|
64
64
|
|
65
65
|
# The font bounding box as array of four numbers, specifying the x- and y-coordinates of the
|
66
|
-
# bottom
|
66
|
+
# bottom-left corner and the x- and y-coordinates of the top-right corner.
|
67
67
|
attr_accessor :bounding_box
|
68
68
|
|
69
69
|
# The y-value of the top of the capital H (or 0 or nil if the font doesn't contain a capital
|