hexapdf 0.9.3 → 0.10.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 +35 -0
- data/CONTRIBUTERS +2 -1
- data/VERSION +1 -1
- data/lib/hexapdf/cli/command.rb +9 -5
- data/lib/hexapdf/cli/images.rb +68 -13
- data/lib/hexapdf/cli/inspect.rb +201 -71
- data/lib/hexapdf/content/canvas.rb +1 -1
- data/lib/hexapdf/dictionary.rb +15 -1
- data/lib/hexapdf/dictionary_fields.rb +5 -4
- data/lib/hexapdf/document.rb +15 -6
- data/lib/hexapdf/encryption/security_handler.rb +3 -2
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +165 -165
- data/lib/hexapdf/font/true_type_wrapper.rb +2 -2
- data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
- data/lib/hexapdf/image_loader/jpeg.rb +13 -11
- data/lib/hexapdf/reference.rb +5 -0
- data/lib/hexapdf/revision.rb +14 -0
- data/lib/hexapdf/serializer.rb +6 -6
- data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
- data/lib/hexapdf/type/image.rb +3 -1
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/xref_section.rb +8 -0
- data/man/man1/hexapdf.1 +88 -20
- data/test/data/images/truecolour-alpha-8bit.png +0 -0
- data/test/data/images/ycck.jpg +0 -0
- data/test/hexapdf/content/test_canvas.rb +2 -2
- data/test/hexapdf/document/test_images.rb +7 -5
- data/test/hexapdf/encryption/test_security_handler.rb +13 -0
- data/test/hexapdf/image_loader/test_jpeg.rb +10 -0
- data/test/hexapdf/image_loader/test_png.rb +3 -2
- data/test/hexapdf/test_dictionary.rb +9 -0
- data/test/hexapdf/test_dictionary_fields.rb +15 -0
- data/test/hexapdf/test_document.rb +5 -2
- data/test/hexapdf/test_reference.rb +4 -0
- data/test/hexapdf/test_revision.rb +12 -0
- data/test/hexapdf/test_writer.rb +5 -5
- data/test/hexapdf/test_xref_section.rb +11 -0
- data/test/hexapdf/type/test_form.rb +1 -1
- data/test/hexapdf/type/test_image.rb +28 -19
- metadata +3 -2
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'test_helper'
|
4
4
|
require 'hexapdf/dictionary_fields'
|
5
5
|
require 'hexapdf/dictionary'
|
6
|
+
require 'hexapdf/stream'
|
6
7
|
require 'hexapdf/type'
|
7
8
|
|
8
9
|
describe HexaPDF::DictionaryFields do
|
@@ -74,6 +75,20 @@ describe HexaPDF::DictionaryFields do
|
|
74
75
|
@doc.verify
|
75
76
|
end
|
76
77
|
|
78
|
+
it "allows conversion from an HexaPDF::Dictionary to a Stream if stream data is set" do
|
79
|
+
@field = self.class::Field.new(HexaPDF::Stream)
|
80
|
+
@doc.expect(:wrap, :data, [HexaPDF::Dictionary, Hash])
|
81
|
+
data = HexaPDF::PDFData.new({}, 0, 0, "")
|
82
|
+
@field.convert(HexaPDF::Dictionary.new(data), @doc)
|
83
|
+
@doc.verify
|
84
|
+
end
|
85
|
+
|
86
|
+
it "doesn't allow conversion to a Stream subclass from Hash or Dictionary" do
|
87
|
+
@field = self.class::Field.new(HexaPDF::Stream)
|
88
|
+
refute(@field.convert({}, @doc))
|
89
|
+
refute(@field.convert(HexaPDF::Dictionary.new(Test: :value), @doc))
|
90
|
+
end
|
91
|
+
|
77
92
|
it "doesn't allow conversion from nil" do
|
78
93
|
refute(@field.convert(nil, @doc))
|
79
94
|
end
|
@@ -267,6 +267,7 @@ describe HexaPDF::Document do
|
|
267
267
|
@myclass = Class.new(HexaPDF::Dictionary)
|
268
268
|
@myclass.define_type(:MyClass)
|
269
269
|
@myclass2 = Class.new(HexaPDF::Dictionary)
|
270
|
+
@myclass2.define_field(:Test, type: String, required: true)
|
270
271
|
HexaPDF::GlobalConfiguration['object.type_map'][:MyClass] = @myclass
|
271
272
|
HexaPDF::GlobalConfiguration['object.subtype_map'][nil][:Global] = @myclass2
|
272
273
|
HexaPDF::GlobalConfiguration['object.subtype_map'][:MyClass] = {TheSecond: @myclass2}
|
@@ -328,14 +329,16 @@ describe HexaPDF::Document do
|
|
328
329
|
it "uses the type/subtype information in the hash that should be wrapped" do
|
329
330
|
assert_kind_of(@myclass, @doc.wrap(Type: :MyClass))
|
330
331
|
refute_kind_of(@myclass2, @doc.wrap(Subtype: :TheSecond))
|
331
|
-
|
332
|
+
refute_kind_of(@myclass2, @doc.wrap(Subtype: :Global))
|
333
|
+
assert_kind_of(@myclass2, @doc.wrap(Subtype: :Global, Test: "true"))
|
332
334
|
assert_kind_of(@myclass2, @doc.wrap(Type: :MyClass, S: :TheSecond))
|
333
335
|
assert_kind_of(@myclass, @doc.wrap(Type: :MyClass, Subtype: :TheThird))
|
334
336
|
end
|
335
337
|
|
336
338
|
it "respects the given type/subtype arguments" do
|
337
339
|
assert_kind_of(@myclass, @doc.wrap({Type: :Other}, type: :MyClass))
|
338
|
-
|
340
|
+
refute_kind_of(@myclass2, @doc.wrap({Subtype: :Other}, subtype: :Global))
|
341
|
+
assert_kind_of(@myclass2, @doc.wrap({Subtype: :Other, Test: "true"}, subtype: :Global))
|
339
342
|
assert_kind_of(@myclass2, @doc.wrap({Type: :Other, Subtype: :Other},
|
340
343
|
type: :MyClass, subtype: :TheSecond))
|
341
344
|
assert_kind_of(@myclass2, @doc.wrap({Subtype: :TheSecond}, type: @myclass))
|
@@ -40,6 +40,10 @@ describe HexaPDF::Reference do
|
|
40
40
|
refute(h.key?(HexaPDF::Reference.new(5, 8)))
|
41
41
|
end
|
42
42
|
|
43
|
+
it "shows the PDF serialization as string representation " do
|
44
|
+
assert_equal("5 7 R", HexaPDF::Reference.new(5, 7).to_s)
|
45
|
+
end
|
46
|
+
|
43
47
|
it "shows oid and gen on inspection" do
|
44
48
|
assert_match(/\[5, 7\]/, HexaPDF::Reference.new(5, 7).inspect)
|
45
49
|
end
|
@@ -63,6 +63,18 @@ describe HexaPDF::Revision do
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
describe "xref" do
|
67
|
+
it "returns the xref structure" do
|
68
|
+
assert_equal(@xref_section[2, 0], @rev.xref(HexaPDF::Reference.new(2, 0)))
|
69
|
+
assert_equal(@xref_section[2, 0], @rev.xref(2))
|
70
|
+
end
|
71
|
+
|
72
|
+
it "returns nil if no xref entry is found" do
|
73
|
+
assert_nil(@rev.xref(@ref))
|
74
|
+
assert_nil(@rev.xref(1))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
66
78
|
describe "object" do
|
67
79
|
it "returns nil if no object is found" do
|
68
80
|
assert_nil(@rev.object(@ref))
|
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.10.0)>>
|
44
44
|
endobj
|
45
45
|
xref
|
46
46
|
3 1
|
@@ -48,7 +48,7 @@ describe HexaPDF::Writer do
|
|
48
48
|
trailer
|
49
49
|
<</Prev 219/Size 4/Root<</Type/Catalog>>/Info 3 0 R>>
|
50
50
|
startxref
|
51
|
-
|
51
|
+
349
|
52
52
|
%%EOF
|
53
53
|
EOF
|
54
54
|
|
@@ -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.10.0)>>
|
76
76
|
endobj
|
77
77
|
2 0 obj
|
78
78
|
<</Length 10>>stream
|
@@ -81,11 +81,11 @@ describe HexaPDF::Writer do
|
|
81
81
|
endobj
|
82
82
|
4 0 obj
|
83
83
|
<</Size 7/Prev 141/Root<</Type/Catalog>>/Info 6 0 R/Type/XRef/W[1 2 2]/Index[2 1 4 1 6 1]/Filter/FlateDecode/DecodeParms<</Columns 5/Predictor 12>>/Length 22>>stream
|
84
|
-
x\
|
84
|
+
x\xDAcbdlg``b`\xB0\x04\x93\x93\x18\x18\x00\f\e\x01[
|
85
85
|
endstream
|
86
86
|
endobj
|
87
87
|
startxref
|
88
|
-
|
88
|
+
448
|
89
89
|
%%EOF
|
90
90
|
EOF
|
91
91
|
end
|
@@ -3,6 +3,17 @@
|
|
3
3
|
require 'test_helper'
|
4
4
|
require 'hexapdf/xref_section'
|
5
5
|
|
6
|
+
describe HexaPDF::XRefSection::Entry do
|
7
|
+
it "can describe itself" do
|
8
|
+
free = HexaPDF::XRefSection::Entry.new(:free, 1, 2)
|
9
|
+
normal = HexaPDF::XRefSection::Entry.new(:in_use, 1, 2, 10)
|
10
|
+
compressed = HexaPDF::XRefSection::Entry.new(:compressed, 1, 0, 2, 10)
|
11
|
+
assert_match(/1,2 type=free/, free.to_s)
|
12
|
+
assert_match(/1,2 type=normal/, normal.to_s)
|
13
|
+
assert_match(/1,0 type=compressed/, compressed.to_s)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
6
17
|
describe HexaPDF::XRefSection do
|
7
18
|
before do
|
8
19
|
@xref_section = HexaPDF::XRefSection.new
|
@@ -12,19 +12,19 @@ describe HexaPDF::Type::Image do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "returns the width of the image" do
|
15
|
-
@image = @doc.wrap(Subtype: :Image, Width: 10)
|
15
|
+
@image = @doc.wrap(Type: :XObject, Subtype: :Image, Width: 10)
|
16
16
|
assert_equal(10, @image.width)
|
17
17
|
end
|
18
18
|
|
19
19
|
it "returns the height of the image" do
|
20
|
-
@image = @doc.wrap(Subtype: :Image, Height: 10)
|
20
|
+
@image = @doc.wrap(Type: :XObject, Subtype: :Image, Height: 10)
|
21
21
|
assert_equal(10, @image.height)
|
22
22
|
end
|
23
23
|
|
24
24
|
describe "info" do
|
25
25
|
before do
|
26
|
-
@image = @doc.wrap(Subtype: :Image, Width: 10, Height: 5,
|
27
|
-
BitsPerComponent: 4)
|
26
|
+
@image = @doc.wrap(Type: :XObject, Subtype: :Image, Width: 10, Height: 5,
|
27
|
+
ColorSpace: :DeviceRGB, BitsPerComponent: 4)
|
28
28
|
end
|
29
29
|
|
30
30
|
it "uses the Width, Height and BitsPerComponent values" do
|
@@ -131,18 +131,24 @@ describe HexaPDF::Type::Image do
|
|
131
131
|
@file.unlink
|
132
132
|
end
|
133
133
|
|
134
|
-
`pngcheck 2>&1`
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
PNG_CHECK_AVAILABLE = true
|
140
|
-
end
|
134
|
+
`which pngcheck 2>&1`
|
135
|
+
PNG_CHECK_AVAILABLE = $?.exitstatus == 0
|
136
|
+
|
137
|
+
`which pngtopnm 2>&1`
|
138
|
+
PNG_COMPARE_AVAILABLE = $?.exitstatus == 0
|
141
139
|
|
142
|
-
def assert_valid_png(filename)
|
143
|
-
|
144
|
-
|
145
|
-
|
140
|
+
def assert_valid_png(filename, original = nil)
|
141
|
+
if PNG_CHECK_AVAILABLE
|
142
|
+
result = `pngcheck -q #{filename}`
|
143
|
+
assert(result.empty?, "pngcheck error: #{result}")
|
144
|
+
else
|
145
|
+
skip("Skipping PNG output validity check because pngcheck executable is missing")
|
146
|
+
end
|
147
|
+
if PNG_COMPARE_AVAILABLE
|
148
|
+
assert_equal(`pngtopnm #{original}`, `pngtopnm #{filename}`) if original
|
149
|
+
else
|
150
|
+
skip("Skipping PNG output comparison check because pngtopnm executable is missing")
|
151
|
+
end
|
146
152
|
end
|
147
153
|
|
148
154
|
it "can write to an IO" do
|
@@ -179,8 +185,11 @@ describe HexaPDF::Type::Image do
|
|
179
185
|
it "writes #{File.basename(png_file)} correctly as PNG file" do
|
180
186
|
image = @doc.images.add(png_file)
|
181
187
|
image.write(@file.path)
|
188
|
+
assert_valid_png(@file.path, png_file)
|
182
189
|
|
183
|
-
|
190
|
+
image.delete(:DecodeParms) # force re-encoding of stream
|
191
|
+
image.write(@file.path)
|
192
|
+
assert_valid_png(@file.path, png_file)
|
184
193
|
|
185
194
|
new_image = @doc.images.add(@file.path)
|
186
195
|
|
@@ -208,7 +217,7 @@ describe HexaPDF::Type::Image do
|
|
208
217
|
end
|
209
218
|
|
210
219
|
it "works for greyscale indexed images" do
|
211
|
-
image = @doc.add(Subtype: :Image, Width: 2, Height: 2, BitsPerComponent: 2,
|
220
|
+
image = @doc.add(Type: :XObject, Subtype: :Image, Width: 2, Height: 2, BitsPerComponent: 2,
|
212
221
|
ColorSpace: [:Indexed, :DeviceGray, 3, "\x00\x40\x80\xFF".b])
|
213
222
|
image.stream = HexaPDF::StreamData.new(filter: :ASCIIHexDecode) { "10 B0".b }
|
214
223
|
image.write(@file.path)
|
@@ -227,13 +236,13 @@ describe HexaPDF::Type::Image do
|
|
227
236
|
end
|
228
237
|
|
229
238
|
it "fails if an unsupported colorspace is used" do
|
230
|
-
image = @doc.add(Subtype: :Image, Width: 1, Height: 1, BitsPerComponent: 8,
|
239
|
+
image = @doc.add(Type: :XObject, Subtype: :Image, Width: 1, Height: 1, BitsPerComponent: 8,
|
231
240
|
ColorSpace: :ICCBased)
|
232
241
|
assert_raises(HexaPDF::Error) { image.write(@file) }
|
233
242
|
end
|
234
243
|
|
235
244
|
it "fails if an indexed image with an unsupported colorspace is used" do
|
236
|
-
image = @doc.add(Subtype: :Image, Width: 1, Height: 1, BitsPerComponent: 8,
|
245
|
+
image = @doc.add(Type: :XObject, Subtype: :Image, Width: 1, Height: 1, BitsPerComponent: 8,
|
237
246
|
ColorSpace: [:Indexed, :ICCBased, 0, "0"])
|
238
247
|
assert_raises(HexaPDF::Error) { image.write(@file) }
|
239
248
|
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.10.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: 2019-
|
11
|
+
date: 2019-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cmdparse
|
@@ -436,6 +436,7 @@ files:
|
|
436
436
|
- test/data/images/truecolour-alpha-8bit.png
|
437
437
|
- test/data/images/truecolour-gama-chrm-8bit.png
|
438
438
|
- test/data/images/truecolour-srgb-8bit.png
|
439
|
+
- test/data/images/ycck.jpg
|
439
440
|
- test/data/minimal.pdf
|
440
441
|
- test/data/standard-security-handler/README
|
441
442
|
- test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf
|