hexapdf 0.8.0 → 0.9.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 +52 -1
- data/CONTRIBUTERS +1 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/examples/018-composer.rb +44 -0
- data/lib/hexapdf/cli.rb +2 -0
- data/lib/hexapdf/cli/command.rb +2 -2
- data/lib/hexapdf/cli/optimize.rb +1 -1
- data/lib/hexapdf/cli/split.rb +82 -0
- data/lib/hexapdf/composer.rb +303 -0
- data/lib/hexapdf/configuration.rb +2 -2
- data/lib/hexapdf/content/canvas.rb +3 -6
- data/lib/hexapdf/dictionary.rb +0 -3
- data/lib/hexapdf/document.rb +30 -22
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/images.rb +1 -1
- data/lib/hexapdf/filter/predictor.rb +8 -8
- data/lib/hexapdf/layout.rb +1 -0
- data/lib/hexapdf/layout/box.rb +55 -12
- data/lib/hexapdf/layout/frame.rb +143 -46
- data/lib/hexapdf/layout/image_box.rb +96 -0
- data/lib/hexapdf/layout/inline_box.rb +10 -0
- data/lib/hexapdf/layout/line.rb +1 -1
- data/lib/hexapdf/layout/style.rb +55 -3
- data/lib/hexapdf/layout/text_box.rb +38 -8
- data/lib/hexapdf/layout/text_layouter.rb +66 -52
- data/lib/hexapdf/object.rb +3 -2
- data/lib/hexapdf/parser.rb +6 -1
- data/lib/hexapdf/rectangle.rb +6 -0
- data/lib/hexapdf/reference.rb +4 -6
- data/lib/hexapdf/revision.rb +34 -8
- data/lib/hexapdf/revisions.rb +12 -2
- data/lib/hexapdf/stream.rb +18 -0
- data/lib/hexapdf/task.rb +1 -1
- data/lib/hexapdf/task/dereference.rb +1 -1
- data/lib/hexapdf/task/optimize.rb +2 -2
- data/lib/hexapdf/type/form.rb +10 -0
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/writer.rb +25 -5
- data/man/man1/hexapdf.1 +17 -0
- data/test/hexapdf/layout/test_box.rb +7 -1
- data/test/hexapdf/layout/test_frame.rb +38 -1
- data/test/hexapdf/layout/test_image_box.rb +73 -0
- data/test/hexapdf/layout/test_inline_box.rb +8 -0
- data/test/hexapdf/layout/test_line.rb +1 -1
- data/test/hexapdf/layout/test_style.rb +58 -1
- data/test/hexapdf/layout/test_text_box.rb +57 -12
- data/test/hexapdf/layout/test_text_layouter.rb +14 -4
- data/test/hexapdf/task/test_optimize.rb +3 -3
- data/test/hexapdf/test_composer.rb +258 -0
- data/test/hexapdf/test_document.rb +29 -3
- data/test/hexapdf/test_importer.rb +8 -2
- data/test/hexapdf/test_object.rb +3 -1
- data/test/hexapdf/test_parser.rb +6 -0
- data/test/hexapdf/test_rectangle.rb +7 -0
- data/test/hexapdf/test_reference.rb +3 -1
- data/test/hexapdf/test_revision.rb +13 -0
- data/test/hexapdf/test_revisions.rb +1 -0
- data/test/hexapdf/test_stream.rb +13 -0
- data/test/hexapdf/test_writer.rb +13 -2
- data/test/hexapdf/type/test_annotation.rb +1 -1
- data/test/hexapdf/type/test_form.rb +13 -2
- metadata +10 -4
@@ -386,17 +386,22 @@ describe HexaPDF::Document do
|
|
386
386
|
|
387
387
|
describe "each" do
|
388
388
|
it "iterates over the current objects" do
|
389
|
-
assert_equal([10, 200, nil], @io_doc.each(
|
389
|
+
assert_equal([10, 200, nil], @io_doc.each(only_current: true).sort.map(&:value))
|
390
390
|
end
|
391
391
|
|
392
392
|
it "iterates over all objects" do
|
393
|
-
assert_equal([10, 200, 20, 30, nil], @io_doc.each(
|
393
|
+
assert_equal([10, 200, 20, 30, nil], @io_doc.each(only_current: false).sort.map(&:value))
|
394
|
+
end
|
395
|
+
|
396
|
+
it "iterates over all loaded objects" do
|
397
|
+
assert_equal(200, @io_doc.object(2).value)
|
398
|
+
assert_equal([200], @io_doc.each(only_loaded: true).sort.map(&:value))
|
394
399
|
end
|
395
400
|
|
396
401
|
it "yields the revision as second argument if the block accepts exactly two arguments" do
|
397
402
|
objs = [[10, 20, 30], [200, nil]]
|
398
403
|
data = @io_doc.revisions.map.with_index {|rev, i| objs[i].map {|o| [o, rev] } }.reverse.flatten
|
399
|
-
@io_doc.each(
|
404
|
+
@io_doc.each(only_current: false) do |obj, rev|
|
400
405
|
assert(data.shift == obj.value)
|
401
406
|
assert_equal(data.shift, rev)
|
402
407
|
end
|
@@ -448,6 +453,21 @@ describe HexaPDF::Document do
|
|
448
453
|
@doc.trailer[:ID] = :Symbol
|
449
454
|
refute(@doc.validate {|obj| assert_same(@doc.trailer, obj) })
|
450
455
|
end
|
456
|
+
|
457
|
+
it "validates only loaded objects" do
|
458
|
+
io = StringIO.new
|
459
|
+
doc = HexaPDF::Document.new
|
460
|
+
doc.pages.add.delete(:Resources)
|
461
|
+
page = doc.pages.add
|
462
|
+
page[:Annots] = [doc.add(Type: :Annot, Subtype: :Link, Rect: [0, 0, 1, 1], H: :Z)]
|
463
|
+
doc.write(io, validate: false)
|
464
|
+
doc = HexaPDF::Document.new(io: io)
|
465
|
+
doc.pages[0] # force loading of the first page
|
466
|
+
|
467
|
+
refute(doc.validate(auto_correct: false, only_loaded: true)) # bc of Resources
|
468
|
+
assert(doc.validate(only_loaded: true))
|
469
|
+
refute(doc.validate(auto_correct: false)) # bc of annot key H
|
470
|
+
end
|
451
471
|
end
|
452
472
|
|
453
473
|
describe "write" do
|
@@ -470,6 +490,12 @@ describe HexaPDF::Document do
|
|
470
490
|
refute(io.string.empty?)
|
471
491
|
end
|
472
492
|
|
493
|
+
it "writes the document incrementally" do
|
494
|
+
io = StringIO.new
|
495
|
+
@io_doc.write(io, incremental: true)
|
496
|
+
assert_equal(@io.string, io.string[0, @io.string.length])
|
497
|
+
end
|
498
|
+
|
473
499
|
it "fails if the document is not valid" do
|
474
500
|
@doc.trailer[:Size] = :Symbol
|
475
501
|
assert_raises(HexaPDF::Error) { @doc.write(StringIO.new(''.b)) }
|
@@ -6,8 +6,14 @@ require 'hexapdf/document'
|
|
6
6
|
|
7
7
|
describe HexaPDF::Importer::NullableWeakRef do
|
8
8
|
it "returns nil instead of an error when the referred-to object is GCed" do
|
9
|
-
|
10
|
-
|
9
|
+
refs = []
|
10
|
+
obj = nil
|
11
|
+
100.times do
|
12
|
+
refs << HexaPDF::Importer::NullableWeakRef.new(Object.new)
|
13
|
+
ObjectSpace.garbage_collect
|
14
|
+
ObjectSpace.garbage_collect
|
15
|
+
break if (obj = refs.find {|ref| !ref.weakref_alive? })
|
16
|
+
end
|
11
17
|
assert_equal("", obj.to_s)
|
12
18
|
end
|
13
19
|
end
|
data/test/hexapdf/test_object.rb
CHANGED
@@ -135,7 +135,7 @@ describe HexaPDF::Object do
|
|
135
135
|
assert_match(/\[5, 0\].*value=5/, obj.inspect)
|
136
136
|
end
|
137
137
|
|
138
|
-
it "can be compared to another object" do
|
138
|
+
it "can be compared to another object or reference" do
|
139
139
|
obj = HexaPDF::Object.new(5, oid: 5)
|
140
140
|
|
141
141
|
assert_equal(obj, HexaPDF::Object.new(obj))
|
@@ -143,6 +143,8 @@ describe HexaPDF::Object do
|
|
143
143
|
refute_equal(obj, HexaPDF::Object.new(6, oid: 5))
|
144
144
|
refute_equal(obj, HexaPDF::Object.new(5, oid: 1))
|
145
145
|
refute_equal(obj, HexaPDF::Object.new(5, oid: 5, gen: 1))
|
146
|
+
|
147
|
+
assert_equal(obj, HexaPDF::Reference.new(5, 0))
|
146
148
|
end
|
147
149
|
|
148
150
|
it "works correctly as hash key, is interchangable in this regard with Reference objects" do
|
data/test/hexapdf/test_parser.rb
CHANGED
@@ -194,6 +194,12 @@ describe HexaPDF::Parser do
|
|
194
194
|
end
|
195
195
|
|
196
196
|
describe "startxref_offset" do
|
197
|
+
it "caches the offset value" do
|
198
|
+
assert_equal(308, @parser.startxref_offset)
|
199
|
+
@parser.instance_eval { @io }.string.sub!(/308\n/, "309\n")
|
200
|
+
assert_equal(308, @parser.startxref_offset)
|
201
|
+
end
|
202
|
+
|
197
203
|
it "returns the correct offset" do
|
198
204
|
assert_equal(308, @parser.startxref_offset)
|
199
205
|
end
|
@@ -35,6 +35,13 @@ describe HexaPDF::Rectangle do
|
|
35
35
|
assert_equal(4, rect.height)
|
36
36
|
end
|
37
37
|
|
38
|
+
it "allows comparison to arrays" do
|
39
|
+
rect = HexaPDF::Rectangle.new([0, 1, 2, 5])
|
40
|
+
assert(rect == [0, 1, 2, 5])
|
41
|
+
rect.oid = 5
|
42
|
+
refute(rect == [0, 1, 2, 5])
|
43
|
+
end
|
44
|
+
|
38
45
|
describe "validation" do
|
39
46
|
it "ensures that it is a correct PDF rectangle" do
|
40
47
|
doc = HexaPDF::Document.new
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'test_helper'
|
4
4
|
require 'hexapdf/reference'
|
5
|
+
require 'hexapdf/object'
|
5
6
|
|
6
7
|
describe HexaPDF::Reference do
|
7
8
|
it "correctly assigns oid and gen on initialization" do
|
@@ -25,10 +26,11 @@ describe HexaPDF::Reference do
|
|
25
26
|
assert_nil(HexaPDF::Reference.new(1, 0) <=> 5)
|
26
27
|
end
|
27
28
|
|
28
|
-
it "is comparable to
|
29
|
+
it "is comparable to objects that have an oid and gen" do
|
29
30
|
assert_equal(HexaPDF::Reference.new(5, 7), HexaPDF::Reference.new(5, 7))
|
30
31
|
refute_equal(HexaPDF::Reference.new(5, 7), HexaPDF::Reference.new(5, 8))
|
31
32
|
refute_equal(HexaPDF::Reference.new(5, 7), HexaPDF::Reference.new(4, 7))
|
33
|
+
assert_equal(HexaPDF::Reference.new(5, 7), HexaPDF::Object.new(:data, oid: 5, gen: 7))
|
32
34
|
end
|
33
35
|
|
34
36
|
it "behaves correctly as hash key" do
|
@@ -125,6 +125,11 @@ describe HexaPDF::Revision do
|
|
125
125
|
obj3 = @rev.object(3)
|
126
126
|
assert_equal([@obj, obj2, obj3], @rev.each.to_a)
|
127
127
|
end
|
128
|
+
|
129
|
+
it "iterates only over loaded objects" do
|
130
|
+
obj = @rev.object(2)
|
131
|
+
assert_equal([obj], @rev.each(only_loaded: true).to_a)
|
132
|
+
end
|
128
133
|
end
|
129
134
|
|
130
135
|
it "works without a cross-reference section" do
|
@@ -136,4 +141,12 @@ describe HexaPDF::Revision do
|
|
136
141
|
rev.delete(@ref, mark_as_free: false)
|
137
142
|
refute(rev.object?(@ref))
|
138
143
|
end
|
144
|
+
|
145
|
+
it "can iterate over all modified objects" do
|
146
|
+
obj = @rev.object(2)
|
147
|
+
assert_equal([], @rev.each_modified_object.to_a)
|
148
|
+
obj.value = :Other
|
149
|
+
@rev.add(@obj)
|
150
|
+
assert_equal([obj, @obj], @rev.each_modified_object.to_a)
|
151
|
+
end
|
139
152
|
end
|
@@ -118,6 +118,7 @@ describe HexaPDF::Revisions do
|
|
118
118
|
|
119
119
|
describe "initialize" do
|
120
120
|
it "automatically loads all revisions from the underlying IO object" do
|
121
|
+
assert_kind_of(HexaPDF::Parser, @revisions.parser)
|
121
122
|
assert_equal(20, @revisions.revision(0).object(2).value)
|
122
123
|
assert_equal(300, @revisions[1].object(2).value)
|
123
124
|
assert_equal(400, @revisions[2].object(2).value)
|
data/test/hexapdf/test_stream.rb
CHANGED
@@ -58,6 +58,19 @@ describe HexaPDF::StreamData do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
61
|
+
|
62
|
+
describe "==" do
|
63
|
+
it "compares with other stream data objects" do
|
64
|
+
s = HexaPDF::StreamData.new(:source, decode_parms: [:a, nil, :b])
|
65
|
+
assert_equal(s, HexaPDF::StreamData.new(:source, decode_parms: [:a, nil, :b]))
|
66
|
+
refute_equal(s, HexaPDF::StreamData.new(:source, decode_parms: [:a, :b]))
|
67
|
+
refute_equal(s, HexaPDF::StreamData.new(:source, decode_parms: [:a, nil, :b], offset: 5))
|
68
|
+
end
|
69
|
+
|
70
|
+
it "returns false if compared with an other object of a different class" do
|
71
|
+
refute_equal(:source, HexaPDF::StreamData.new(:source))
|
72
|
+
end
|
73
|
+
end
|
61
74
|
end
|
62
75
|
|
63
76
|
describe HexaPDF::Stream do
|
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.9.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.9.0)>>
|
76
76
|
endobj
|
77
77
|
2 0 obj
|
78
78
|
<</Length 10>>stream
|
@@ -103,6 +103,17 @@ describe HexaPDF::Writer do
|
|
103
103
|
assert_document_conversion(@compressed_input_io)
|
104
104
|
end
|
105
105
|
|
106
|
+
it "writes a document in incremental mode" do
|
107
|
+
doc = HexaPDF::Document.new(io: @std_input_io)
|
108
|
+
doc.pages.add
|
109
|
+
output_io = StringIO.new
|
110
|
+
HexaPDF::Writer.write(doc, output_io, incremental: true)
|
111
|
+
assert_equal(output_io.string[0, @std_input_io.string.length], @std_input_io.string)
|
112
|
+
doc = HexaPDF::Document.new(io: output_io)
|
113
|
+
assert_equal(4, doc.revisions.size)
|
114
|
+
assert_equal(2, doc.revisions.current.each.to_a.size)
|
115
|
+
end
|
116
|
+
|
106
117
|
it "raises an error if no xref stream is in a revision but object streams are" do
|
107
118
|
document = HexaPDF::Document.new
|
108
119
|
document.add(Type: :ObjStm)
|
@@ -12,9 +12,20 @@ describe HexaPDF::Type::Form do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
describe "box" do
|
15
|
+
before do
|
16
|
+
@form[:BBox] = [10, 10, 110, 60]
|
17
|
+
end
|
18
|
+
|
15
19
|
it "returns the /BBox entry" do
|
16
|
-
|
17
|
-
|
20
|
+
assert_equal([10, 10, 110, 60], @form.box.value)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns the box's width" do
|
24
|
+
assert_equal(100, @form.width)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "returns the box's height" do
|
28
|
+
assert_equal(50, @form.height)
|
18
29
|
end
|
19
30
|
end
|
20
31
|
|
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.9.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: 2018-
|
11
|
+
date: 2018-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cmdparse
|
@@ -36,14 +36,14 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '0.
|
39
|
+
version: '0.2'
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '0.
|
46
|
+
version: '0.2'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: kramdown
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -205,6 +205,7 @@ files:
|
|
205
205
|
- examples/015-boxes.rb
|
206
206
|
- examples/016-frame_automatic_box_placement.rb
|
207
207
|
- examples/017-frame_text_flow.rb
|
208
|
+
- examples/018-composer.rb
|
208
209
|
- examples/emoji-smile.png
|
209
210
|
- examples/emoji-wink.png
|
210
211
|
- examples/machupicchu.jpg
|
@@ -219,6 +220,8 @@ files:
|
|
219
220
|
- lib/hexapdf/cli/merge.rb
|
220
221
|
- lib/hexapdf/cli/modify.rb
|
221
222
|
- lib/hexapdf/cli/optimize.rb
|
223
|
+
- lib/hexapdf/cli/split.rb
|
224
|
+
- lib/hexapdf/composer.rb
|
222
225
|
- lib/hexapdf/configuration.rb
|
223
226
|
- lib/hexapdf/content.rb
|
224
227
|
- lib/hexapdf/content/canvas.rb
|
@@ -315,6 +318,7 @@ files:
|
|
315
318
|
- lib/hexapdf/layout.rb
|
316
319
|
- lib/hexapdf/layout/box.rb
|
317
320
|
- lib/hexapdf/layout/frame.rb
|
321
|
+
- lib/hexapdf/layout/image_box.rb
|
318
322
|
- lib/hexapdf/layout/inline_box.rb
|
319
323
|
- lib/hexapdf/layout/line.rb
|
320
324
|
- lib/hexapdf/layout/numeric_refinements.rb
|
@@ -533,6 +537,7 @@ files:
|
|
533
537
|
- test/hexapdf/image_loader/test_png.rb
|
534
538
|
- test/hexapdf/layout/test_box.rb
|
535
539
|
- test/hexapdf/layout/test_frame.rb
|
540
|
+
- test/hexapdf/layout/test_image_box.rb
|
536
541
|
- test/hexapdf/layout/test_inline_box.rb
|
537
542
|
- test/hexapdf/layout/test_line.rb
|
538
543
|
- test/hexapdf/layout/test_style.rb
|
@@ -543,6 +548,7 @@ files:
|
|
543
548
|
- test/hexapdf/layout/test_width_from_polygon.rb
|
544
549
|
- test/hexapdf/task/test_dereference.rb
|
545
550
|
- test/hexapdf/task/test_optimize.rb
|
551
|
+
- test/hexapdf/test_composer.rb
|
546
552
|
- test/hexapdf/test_configuration.rb
|
547
553
|
- test/hexapdf/test_data_dir.rb
|
548
554
|
- test/hexapdf/test_dictionary.rb
|