hexapdf 0.29.0 → 0.30.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 +18 -0
- data/lib/hexapdf/dictionary_fields.rb +7 -2
- data/lib/hexapdf/document/pages.rb +35 -18
- data/lib/hexapdf/encryption/standard_security_handler.rb +2 -2
- data/lib/hexapdf/type/font_simple.rb +14 -2
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/document/test_pages.rb +25 -0
- data/test/hexapdf/encryption/test_standard_security_handler.rb +2 -2
- data/test/hexapdf/test_dictionary_fields.rb +9 -4
- data/test/hexapdf/test_writer.rb +6 -6
- data/test/hexapdf/type/test_font_simple.rb +18 -6
- 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: 139f1864e4decd05c57468dc3b326a9cc4e749f1d35d4b5dadb3e0549215afd6
|
4
|
+
data.tar.gz: e7a0d34979abe6738a084dec2334f449ebc1db3eb479dd5f2374a81eeabd83d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 339c38737585eafdf447f7516a52ba7ce40b7e2e476336a2404e97a97645d5043b2956835d874296841b8b68d5935c53d97244ac90a2fd621d0471ce85ae8809
|
7
|
+
data.tar.gz: 4a4c843a32859c639fdf724ca1c6492fa3d387a1c8a92335a2341e82de42a5b9bc30663a3226c1cc0f2ca116dd638071e24b595b323e64fa1e0342d8681199bd
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
## 0.30.0 - 2023-01-13
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* [HexaPDF::Document::Pages#create] for creating a page object without adding it
|
6
|
+
to the page tree
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
|
10
|
+
* `HexaPDF::Type::FontSimple#perform_validation` to correct /Widths fields in
|
11
|
+
case it has an invalid number of entries
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
|
15
|
+
* [HexaPDF::DictionaryFields::DateConverter] to handle invalid months, day,
|
16
|
+
hour, minute and second values
|
17
|
+
|
18
|
+
|
1
19
|
## 0.29.0 - 2023-01-30
|
2
20
|
|
3
21
|
### Added
|
@@ -305,8 +305,13 @@ module HexaPDF
|
|
305
305
|
else
|
306
306
|
(m[7] == '-' ? -1 : 1) * (m[8].to_i * 3600 + m[9].to_i * 60).clamp(0, 86399)
|
307
307
|
end
|
308
|
-
|
309
|
-
|
308
|
+
begin
|
309
|
+
Time.new(m[1].to_i, (m[2] ? m[2].to_i : 1), (m[3] ? m[3].to_i : 1),
|
310
|
+
m[4].to_i, m[5].to_i, m[6].to_i, utc_offset)
|
311
|
+
rescue ArgumentError
|
312
|
+
Time.new(m[1].to_i, m[2].to_i.clamp(1, 12), m[3].to_i.clamp(1, 31),
|
313
|
+
m[4].to_i.clamp(0, 23), m[5].to_i.clamp(0, 59), m[6].to_i.clamp(0, 59), utc_offset)
|
314
|
+
end
|
310
315
|
end
|
311
316
|
|
312
317
|
end
|
@@ -75,28 +75,45 @@ module HexaPDF
|
|
75
75
|
@document.catalog.pages
|
76
76
|
end
|
77
77
|
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
78
|
+
# Creates a page object and returns it *without* adding it to the page tree.
|
79
|
+
#
|
80
|
+
# +media_box+::
|
81
|
+
# If this argument is +nil+/not specified, the value is taken from the configuration
|
82
|
+
# option 'page.default_media_box'.
|
83
|
+
#
|
84
|
+
# If the resulting value is an array with four numbers (specifying the media box), the new
|
85
|
+
# page will have these exact dimensions.
|
82
86
|
#
|
83
|
-
#
|
87
|
+
# If the value is a symbol, it is taken as a reference to a pre-defined media box in
|
88
|
+
# HexaPDF::Type::Page::PAPER_SIZE. The +orientation+ can then be used to specify the page
|
89
|
+
# orientation.
|
84
90
|
#
|
85
|
-
#
|
86
|
-
# 'page.
|
91
|
+
# +orientation+::
|
92
|
+
# If this argument is not specified, it is taken from 'page.default_media_orientation'. It
|
93
|
+
# is only used if +media_box+ is a symbol and not an array.
|
94
|
+
def create(media_box: nil, orientation: nil)
|
95
|
+
media_box ||= @document.config['page.default_media_box']
|
96
|
+
orientation ||= @document.config['page.default_media_orientation']
|
97
|
+
box = if media_box.kind_of?(Array)
|
98
|
+
media_box
|
99
|
+
else
|
100
|
+
Type::Page.media_box(media_box, orientation: orientation)
|
101
|
+
end
|
102
|
+
@document.add({Type: :Page, MediaBox: box})
|
103
|
+
end
|
104
|
+
|
105
|
+
# :call-seq:
|
106
|
+
# pages.add -> new_page
|
107
|
+
# pages.add(page) -> page
|
108
|
+
# pages.add(media_box, orientation: nil) -> new_page
|
87
109
|
#
|
88
|
-
#
|
89
|
-
# page will have these dimensions.
|
110
|
+
# Adds the given page or a new empty page at the end and returns it.
|
90
111
|
#
|
91
|
-
# If
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
page = @document.add({Type: :Page, MediaBox: page})
|
97
|
-
elsif page.kind_of?(Symbol)
|
98
|
-
box = Type::Page.media_box(page, orientation: orientation)
|
99
|
-
page = @document.add({Type: :Page, MediaBox: box})
|
112
|
+
# If called with a page object as argument, that page object is used. Otherwise #create is
|
113
|
+
# called with the arguments +media_box+ and +orientation+ to create a new page.
|
114
|
+
def add(page = nil, orientation: nil)
|
115
|
+
unless page.kind_of?(HexaPDF::Type::Page)
|
116
|
+
page = create(media_box: page, orientation: orientation)
|
100
117
|
end
|
101
118
|
@document.catalog.pages.add_page(page)
|
102
119
|
end
|
@@ -324,10 +324,10 @@ module HexaPDF
|
|
324
324
|
def prepare_decryption(password: '', check_permissions: true)
|
325
325
|
if dict[:Filter] != :Standard
|
326
326
|
raise(HexaPDF::UnsupportedEncryptionError,
|
327
|
-
"Invalid /Filter value for standard security handler")
|
327
|
+
"Invalid /Filter value #{dict[:Filter]} for standard security handler")
|
328
328
|
elsif ![2, 3, 4, 6].include?(dict[:R])
|
329
329
|
raise(HexaPDF::UnsupportedEncryptionError,
|
330
|
-
"Invalid /R value for standard security handler")
|
330
|
+
"Invalid /R value #{dict[:R]} for standard security handler")
|
331
331
|
elsif dict[:R] <= 4 && !document.trailer[:ID].kind_of?(PDFArray)
|
332
332
|
document.trailer[:ID] = ['', '']
|
333
333
|
end
|
@@ -171,9 +171,21 @@ module HexaPDF
|
|
171
171
|
yield("Required field #{field} is not set", false) if self[field].nil?
|
172
172
|
end
|
173
173
|
|
174
|
+
widths = self[:Widths]
|
174
175
|
if key?(:Widths) && key?(:LastChar) && key?(:FirstChar) &&
|
175
|
-
|
176
|
-
yield("Invalid number of entries in field Widths",
|
176
|
+
widths.length != (self[:LastChar] - self[:FirstChar] + 1)
|
177
|
+
yield("Invalid number of entries in field Widths", true)
|
178
|
+
difference = self[:LastChar] - self[:FirstChar] + 1 - widths.length
|
179
|
+
if difference > 0
|
180
|
+
missing_value = if widths.count(widths[0]) == widths.length
|
181
|
+
widths[0]
|
182
|
+
else
|
183
|
+
self[:FontDescriptor]&.[](:MissingWidth) || 0
|
184
|
+
end
|
185
|
+
difference.times { widths << missing_value }
|
186
|
+
else
|
187
|
+
widths.slice!(difference, -difference)
|
188
|
+
end
|
177
189
|
end
|
178
190
|
end
|
179
191
|
|
data/lib/hexapdf/version.rb
CHANGED
@@ -14,6 +14,31 @@ describe HexaPDF::Document::Pages do
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
describe "create" do
|
18
|
+
it "uses the defaults from the configuration for missing arguments" do
|
19
|
+
page = @doc.pages.create
|
20
|
+
assert_equal([0, 0, 595, 842], page.box(:media).value)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "allows specifying a reference to a predefined page size" do
|
24
|
+
page = @doc.pages.create(media_box: :A3)
|
25
|
+
assert_equal([0, 0, 842, 1191], page.box(:media).value)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "allows specifying the orientation for a predefined page size" do
|
29
|
+
page = @doc.pages.create(media_box: :A4, orientation: :landscape)
|
30
|
+
assert_equal([0, 0, 842, 595], page.box(:media).value)
|
31
|
+
|
32
|
+
page = @doc.pages.create(orientation: :landscape)
|
33
|
+
assert_equal([0, 0, 842, 595], page.box(:media).value)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "allows using a media box array" do
|
37
|
+
page = @doc.pages.create(media_box: [0, 0, 12, 24], orientation: :landscape)
|
38
|
+
assert_equal([0, 0, 12, 24], page.box(:media).value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
17
42
|
describe "add" do
|
18
43
|
it "adds a new empty page when no page is given" do
|
19
44
|
page = @doc.pages.add
|
@@ -213,14 +213,14 @@ describe HexaPDF::Encryption::StandardSecurityHandler do
|
|
213
213
|
exp = assert_raises(HexaPDF::UnsupportedEncryptionError) do
|
214
214
|
@handler.set_up_decryption({Filter: :NonStandard, V: 2})
|
215
215
|
end
|
216
|
-
assert_match(/Invalid \/Filter/i, exp.message)
|
216
|
+
assert_match(/Invalid \/Filter value NonStandard/i, exp.message)
|
217
217
|
end
|
218
218
|
|
219
219
|
it "fails if the /R value is incorrect" do
|
220
220
|
exp = assert_raises(HexaPDF::UnsupportedEncryptionError) do
|
221
221
|
@handler.set_up_decryption({Filter: :Standard, V: 2, R: 5})
|
222
222
|
end
|
223
|
-
assert_match(/Invalid \/R/i, exp.message)
|
223
|
+
assert_match(/Invalid \/R value 5/i, exp.message)
|
224
224
|
end
|
225
225
|
|
226
226
|
it "fails if the supplied password is invalid" do
|
@@ -188,10 +188,15 @@ describe HexaPDF::DictionaryFields do
|
|
188
188
|
["D:19981223-08'00'", [1998, 12, 23, 00, 00, 00, "-08:00"]],
|
189
189
|
["D:199812-08'00'", [1998, 12, 01, 00, 00, 00, "-08:00"]],
|
190
190
|
["D:1998-08'00'", [1998, 01, 01, 00, 00, 00, "-08:00"]],
|
191
|
-
["D:19981223195210-08", [1998, 12, 23, 19, 52, 10, "-08:00"]], #
|
192
|
-
["D:19981223195210-08'00", [1998, 12, 23, 19, 52, 10, "-08:00"]], #
|
193
|
-
["D:19981223195210-54'00", [1998, 12, 23, 19, 52, 10, "-23:59:59"]], #
|
194
|
-
["D:19981223195210+10'65", [1998, 12, 23, 19, 52, 10, "+11:05"]], #
|
191
|
+
["D:19981223195210-08", [1998, 12, 23, 19, 52, 10, "-08:00"]], # missing '
|
192
|
+
["D:19981223195210-08'00", [1998, 12, 23, 19, 52, 10, "-08:00"]], # missing '
|
193
|
+
["D:19981223195210-54'00", [1998, 12, 23, 19, 52, 10, "-23:59:59"]], # TZ hour too large
|
194
|
+
["D:19981223195210+10'65", [1998, 12, 23, 19, 52, 10, "+11:05"]], # TZ min too large
|
195
|
+
["D:19982423195210-08'00'", [1998, 12, 23, 19, 52, 10, "-08:00"]], # months too large
|
196
|
+
["D:19981273195210-08'00'", [1998, 12, 31, 19, 52, 10, "-08:00"]], # day too large
|
197
|
+
["D:19981223275210-08'00'", [1998, 12, 23, 23, 52, 10, "-08:00"]], # hour too large
|
198
|
+
["D:19981223197710-08'00'", [1998, 12, 23, 19, 59, 10, "-08:00"]], # minute too large
|
199
|
+
["D:19981223195280-08'00'", [1998, 12, 23, 19, 52, 59, "-08:00"]], # seconds too large
|
195
200
|
].each do |str, data|
|
196
201
|
obj = @field.convert(str, self)
|
197
202
|
assert_equal(Time.new(*data), obj, "date str used: #{str}")
|
data/test/hexapdf/test_writer.rb
CHANGED
@@ -40,7 +40,7 @@ describe HexaPDF::Writer do
|
|
40
40
|
219
|
41
41
|
%%EOF
|
42
42
|
3 0 obj
|
43
|
-
<</Producer(HexaPDF version 0.
|
43
|
+
<</Producer(HexaPDF version 0.30.0)>>
|
44
44
|
endobj
|
45
45
|
xref
|
46
46
|
3 1
|
@@ -72,7 +72,7 @@ describe HexaPDF::Writer do
|
|
72
72
|
141
|
73
73
|
%%EOF
|
74
74
|
6 0 obj
|
75
|
-
<</Producer(HexaPDF version 0.
|
75
|
+
<</Producer(HexaPDF version 0.30.0)>>
|
76
76
|
endobj
|
77
77
|
2 0 obj
|
78
78
|
<</Length 10>>stream
|
@@ -164,9 +164,9 @@ describe HexaPDF::Writer do
|
|
164
164
|
|
165
165
|
document = HexaPDF::Document.new(io: io)
|
166
166
|
assert_equal(3, document.revisions.count)
|
167
|
-
assert_equal(1, document.revisions.all[0].object(
|
168
|
-
assert_equal(2, document.revisions.all[1].object(
|
169
|
-
assert_equal(3, document.revisions.all[2].object(
|
167
|
+
assert_equal(1, document.revisions.all[0].object(3)[:Kids].length)
|
168
|
+
assert_equal(2, document.revisions.all[1].object(3)[:Kids].length)
|
169
|
+
assert_equal(3, document.revisions.all[2].object(3)[:Kids].length)
|
170
170
|
end
|
171
171
|
|
172
172
|
it "creates an xref stream if no xref stream is in a revision but object streams are" do
|
@@ -214,7 +214,7 @@ describe HexaPDF::Writer do
|
|
214
214
|
<</Type/Page/MediaBox[0 0 595 842]/Parent 2 0 R/Resources<<>>>>
|
215
215
|
endobj
|
216
216
|
5 0 obj
|
217
|
-
<</Producer(HexaPDF version 0.
|
217
|
+
<</Producer(HexaPDF version 0.30.0)>>
|
218
218
|
endobj
|
219
219
|
4 0 obj
|
220
220
|
<</Root 1 0 R/Info 5 0 R/Size 6/Type/XRef/W[1 1 2]/Index[0 6]/Filter/FlateDecode/DecodeParms<</Columns 4/Predictor 12>>/Length 33>>stream
|
@@ -15,7 +15,7 @@ describe HexaPDF::Type::FontSimple do
|
|
15
15
|
EOF
|
16
16
|
font_descriptor = @doc.add({Type: :FontDescriptor, FontName: :Embedded, Flags: 0b100,
|
17
17
|
FontBBox: [0, 1, 2, 3], ItalicAngle: 0, Ascent: 900,
|
18
|
-
Descent: -100, CapHeight: 800, StemV: 20})
|
18
|
+
MissingWidth: 500, Descent: -100, CapHeight: 800, StemV: 20})
|
19
19
|
@font = @doc.add({Type: :Font, Encoding: :WinAnsiEncoding,
|
20
20
|
BaseFont: :Embedded, FontDescriptor: font_descriptor, ToUnicode: cmap,
|
21
21
|
FirstChar: 32, LastChar: 34, Widths: [600, 0, 700]},
|
@@ -130,9 +130,7 @@ describe HexaPDF::Type::FontSimple do
|
|
130
130
|
end
|
131
131
|
|
132
132
|
it "returns the /MissingWidth of a /FontDescriptor if available and the width was not found" do
|
133
|
-
assert_equal(
|
134
|
-
@font[:FontDescriptor][:MissingWidth] = 99
|
135
|
-
assert_equal(99, @font.width(0))
|
133
|
+
assert_equal(500, @font.width(0))
|
136
134
|
end
|
137
135
|
|
138
136
|
it "returns 0 for a missing code point when FontDescriptor is not available" do
|
@@ -169,8 +167,22 @@ describe HexaPDF::Type::FontSimple do
|
|
169
167
|
end
|
170
168
|
|
171
169
|
it "validates the lengths of the /Widths field" do
|
172
|
-
@font[:Widths] = [65]
|
173
|
-
|
170
|
+
@font[:Widths] = [65, 65]
|
171
|
+
assert(@font.validate)
|
172
|
+
assert_equal([65, 65, 65], @font[:Widths])
|
173
|
+
|
174
|
+
@font[:Widths] = [65, 70]
|
175
|
+
assert(@font.validate)
|
176
|
+
assert_equal([65, 70, 500], @font[:Widths])
|
177
|
+
|
178
|
+
@font[:Widths] = [65, 70]
|
179
|
+
@font.delete(:FontDescriptor)
|
180
|
+
assert(@font.validate)
|
181
|
+
assert_equal([65, 70, 0], @font[:Widths])
|
182
|
+
|
183
|
+
@font[:Widths] = [65, 65, 70, 90, 100]
|
184
|
+
assert(@font.validate)
|
185
|
+
assert_equal([65, 65, 70], @font[:Widths])
|
174
186
|
end
|
175
187
|
end
|
176
188
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hexapdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.30.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Leitner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-02-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cmdparse
|