hexapdf 0.2.0 → 0.3.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 +33 -1
- data/CONTRIBUTERS +1 -1
- data/LICENSE +1 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/hexapdf.rb +1 -1
- data/lib/hexapdf/cli.rb +19 -52
- data/lib/hexapdf/cli/command.rb +251 -0
- data/lib/hexapdf/cli/{extract.rb → files.rb} +19 -23
- data/lib/hexapdf/cli/images.rb +147 -0
- data/lib/hexapdf/cli/info.rb +5 -5
- data/lib/hexapdf/cli/inspect.rb +13 -12
- data/lib/hexapdf/cli/merge.rb +200 -0
- data/lib/hexapdf/cli/modify.rb +39 -242
- data/lib/hexapdf/cli/optimize.rb +104 -0
- data/lib/hexapdf/configuration.rb +1 -1
- data/lib/hexapdf/content.rb +1 -1
- data/lib/hexapdf/content/canvas.rb +1 -1
- data/lib/hexapdf/content/color_space.rb +1 -1
- data/lib/hexapdf/content/graphic_object.rb +1 -1
- data/lib/hexapdf/content/graphic_object/arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
- data/lib/hexapdf/content/graphics_state.rb +1 -1
- data/lib/hexapdf/content/operator.rb +1 -1
- data/lib/hexapdf/content/parser.rb +16 -15
- data/lib/hexapdf/content/processor.rb +1 -1
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/data_dir.rb +1 -1
- data/lib/hexapdf/dictionary.rb +1 -1
- data/lib/hexapdf/dictionary_fields.rb +1 -1
- data/lib/hexapdf/document.rb +1 -1
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +1 -1
- data/lib/hexapdf/document/images.rb +1 -1
- data/lib/hexapdf/document/pages.rb +1 -1
- data/lib/hexapdf/encryption.rb +1 -1
- data/lib/hexapdf/encryption/aes.rb +1 -1
- data/lib/hexapdf/encryption/arc4.rb +1 -1
- data/lib/hexapdf/encryption/fast_aes.rb +1 -1
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/identity.rb +1 -1
- data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
- data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +1 -1
- data/lib/hexapdf/encryption/standard_security_handler.rb +1 -1
- data/lib/hexapdf/error.rb +1 -1
- data/lib/hexapdf/filter.rb +1 -1
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/dct_decode.rb +1 -1
- data/lib/hexapdf/filter/encryption.rb +1 -1
- data/lib/hexapdf/filter/flate_decode.rb +1 -1
- data/lib/hexapdf/filter/jpx_decode.rb +1 -1
- data/lib/hexapdf/filter/lzw_decode.rb +2 -3
- data/lib/hexapdf/filter/predictor.rb +11 -11
- data/lib/hexapdf/filter/run_length_decode.rb +1 -1
- data/lib/hexapdf/font/cmap.rb +1 -1
- data/lib/hexapdf/font/cmap/parser.rb +1 -1
- data/lib/hexapdf/font/cmap/writer.rb +1 -1
- data/lib/hexapdf/font/encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/base.rb +1 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/glyph_list.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
- data/lib/hexapdf/font/true_type.rb +2 -1
- data/lib/hexapdf/font/true_type/font.rb +1 -1
- data/lib/hexapdf/font/true_type/subsetter.rb +186 -0
- data/lib/hexapdf/font/true_type/table.rb +8 -4
- data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
- data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
- data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
- data/lib/hexapdf/font/true_type/table/glyf.rb +6 -2
- data/lib/hexapdf/font/true_type/table/head.rb +2 -2
- data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
- data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
- data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
- data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
- data/lib/hexapdf/font/true_type/table/name.rb +1 -1
- data/lib/hexapdf/font/true_type/table/os2.rb +1 -1
- data/lib/hexapdf/font/true_type/table/post.rb +1 -1
- data/lib/hexapdf/font/true_type_wrapper.rb +56 -8
- data/lib/hexapdf/font/type1.rb +1 -1
- data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
- data/lib/hexapdf/font/type1_wrapper.rb +1 -1
- data/lib/hexapdf/font_loader.rb +1 -1
- data/lib/hexapdf/font_loader/from_configuration.rb +6 -3
- data/lib/hexapdf/font_loader/standard14.rb +1 -1
- data/lib/hexapdf/image_loader.rb +1 -1
- data/lib/hexapdf/image_loader/jpeg.rb +1 -1
- data/lib/hexapdf/image_loader/pdf.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +1 -1
- data/lib/hexapdf/importer.rb +1 -1
- data/lib/hexapdf/name_tree_node.rb +1 -1
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/object.rb +1 -1
- data/lib/hexapdf/parser.rb +1 -1
- data/lib/hexapdf/rectangle.rb +1 -1
- data/lib/hexapdf/reference.rb +1 -1
- data/lib/hexapdf/revision.rb +1 -1
- data/lib/hexapdf/revisions.rb +13 -15
- data/lib/hexapdf/serializer.rb +7 -3
- data/lib/hexapdf/stream.rb +1 -1
- data/lib/hexapdf/task.rb +1 -1
- data/lib/hexapdf/task/dereference.rb +1 -1
- data/lib/hexapdf/task/optimize.rb +1 -1
- data/lib/hexapdf/tokenizer.rb +12 -12
- data/lib/hexapdf/type.rb +1 -1
- data/lib/hexapdf/type/catalog.rb +1 -1
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +1 -1
- data/lib/hexapdf/type/font.rb +1 -1
- data/lib/hexapdf/type/font_descriptor.rb +1 -1
- data/lib/hexapdf/type/font_simple.rb +1 -1
- data/lib/hexapdf/type/font_true_type.rb +1 -1
- data/lib/hexapdf/type/font_type1.rb +1 -1
- data/lib/hexapdf/type/form.rb +1 -1
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/type/image.rb +187 -1
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/names.rb +1 -1
- data/lib/hexapdf/type/object_stream.rb +1 -1
- data/lib/hexapdf/type/page.rb +1 -1
- data/lib/hexapdf/type/page_tree_node.rb +6 -1
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +2 -2
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +22 -18
- data/lib/hexapdf/utils/bit_field.rb +1 -1
- data/lib/hexapdf/utils/bit_stream.rb +16 -32
- data/lib/hexapdf/utils/lru_cache.rb +1 -1
- data/lib/hexapdf/utils/math_helpers.rb +1 -1
- data/lib/hexapdf/utils/object_hash.rb +1 -1
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
- data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
- data/lib/hexapdf/version.rb +2 -2
- data/lib/hexapdf/writer.rb +2 -1
- data/lib/hexapdf/xref_section.rb +6 -1
- data/man/man1/hexapdf.1 +194 -115
- data/test/data/images/greyscale-1bit.png +0 -0
- data/test/data/images/greyscale-2bit.png +0 -0
- data/test/data/images/greyscale-8bit.png +0 -0
- data/test/data/images/indexed-alpha-4bit.png +0 -0
- data/test/data/images/truecolour-8bit.png +0 -0
- data/test/hexapdf/content/test_operator.rb +8 -8
- data/test/hexapdf/content/test_processor.rb +1 -1
- data/test/hexapdf/encryption/test_security_handler.rb +1 -1
- data/test/hexapdf/font/test_true_type_wrapper.rb +89 -48
- data/test/hexapdf/font/true_type/table/test_glyf.rb +1 -0
- data/test/hexapdf/font/true_type/test_subsetter.rb +70 -0
- data/test/hexapdf/font/true_type/test_table.rb +16 -0
- data/test/hexapdf/font_loader/test_from_configuration.rb +7 -0
- data/test/hexapdf/test_document.rb +1 -1
- data/test/hexapdf/test_object.rb +1 -1
- data/test/hexapdf/test_revisions.rb +34 -8
- data/test/hexapdf/test_serializer.rb +3 -0
- data/test/hexapdf/test_writer.rb +11 -2
- data/test/hexapdf/test_xref_section.rb +15 -0
- data/test/hexapdf/type/test_image.rb +234 -0
- data/test/hexapdf/type/test_object_stream.rb +2 -2
- data/test/hexapdf/type/test_trailer.rb +4 -0
- data/test/hexapdf/utils/test_bit_stream.rb +69 -0
- metadata +14 -6
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -521,8 +521,8 @@ describe_operator :MoveTextAndSetLeading, :TD do
|
|
521
521
|
@processor.operators[:Td] = td
|
522
522
|
|
523
523
|
invoke(1.56, 1.78)
|
524
|
-
tl.verify
|
525
|
-
td.verify
|
524
|
+
assert(tl.verify)
|
525
|
+
assert(td.verify)
|
526
526
|
end
|
527
527
|
|
528
528
|
it "serializes correctly" do
|
@@ -554,7 +554,7 @@ describe_operator :MoveTextNextLine, :'T*' do
|
|
554
554
|
|
555
555
|
@processor.graphics_state.leading = 1.78
|
556
556
|
invoke
|
557
|
-
td.verify
|
557
|
+
assert(td.verify)
|
558
558
|
end
|
559
559
|
end
|
560
560
|
|
@@ -576,8 +576,8 @@ describe_operator :MoveTextNextLineAndShowText, :"'" do
|
|
576
576
|
@processor.operators[:Tj] = tj
|
577
577
|
|
578
578
|
invoke(text)
|
579
|
-
tstar.verify
|
580
|
-
tj.verify
|
579
|
+
assert(tstar.verify)
|
580
|
+
assert(tj.verify)
|
581
581
|
end
|
582
582
|
|
583
583
|
it "serializes correctly" do
|
@@ -602,9 +602,9 @@ describe_operator :SetSpacingMoveTextNextLineAndShowText, :'"' do
|
|
602
602
|
@processor.operators[:"'"] = tapos
|
603
603
|
|
604
604
|
invoke(word_spacing, char_spacing, text)
|
605
|
-
tw.verify
|
606
|
-
tc.verify
|
607
|
-
tapos.verify
|
605
|
+
assert(tw.verify)
|
606
|
+
assert(tc.verify)
|
607
|
+
assert(tapos.verify)
|
608
608
|
end
|
609
609
|
|
610
610
|
it "serializes correctly" do
|
@@ -138,7 +138,7 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
138
138
|
[[40, nil], [48, 48], [128, 128], [256, nil]].each do |key_length, result|
|
139
139
|
algorithm = (key_length == 256 ? :aes : :arc4)
|
140
140
|
@handler.set_up_encryption(key_length: key_length, algorithm: algorithm)
|
141
|
-
|
141
|
+
assert(result == @handler.dict[:Length])
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
@@ -7,8 +7,8 @@ require 'hexapdf/document'
|
|
7
7
|
describe HexaPDF::Font::TrueTypeWrapper do
|
8
8
|
before do
|
9
9
|
@doc = HexaPDF::Document.new
|
10
|
-
font_file = File.join(TEST_DATA_DIR, "fonts", "Ubuntu-Title.ttf")
|
11
|
-
@font = HexaPDF::Font::TrueType::Font.new(File.open(font_file))
|
10
|
+
@font_file = File.join(TEST_DATA_DIR, "fonts", "Ubuntu-Title.ttf")
|
11
|
+
@font = HexaPDF::Font::TrueType::Font.new(File.open(@font_file))
|
12
12
|
@cmap = @font[:cmap].preferred_table
|
13
13
|
@font_wrapper = HexaPDF::Font::TrueTypeWrapper.new(@doc, @font)
|
14
14
|
end
|
@@ -24,6 +24,11 @@ describe HexaPDF::Font::TrueTypeWrapper do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
it "can be asked whether font wil be subset" do
|
28
|
+
assert(@font_wrapper.subset?)
|
29
|
+
refute(HexaPDF::Font::TrueTypeWrapper.new(@doc, @font, subset: false).subset?)
|
30
|
+
end
|
31
|
+
|
27
32
|
describe "decode_utf8" do
|
28
33
|
it "returns an array of glyph objects" do
|
29
34
|
assert_equal("Test",
|
@@ -34,7 +39,7 @@ describe HexaPDF::Font::TrueTypeWrapper do
|
|
34
39
|
gotten = nil
|
35
40
|
@doc.config['font.on_missing_glyph'] = proc {|c| gotten = c; 0 }
|
36
41
|
assert_equal([0], @font_wrapper.decode_utf8("😁").map(&:id))
|
37
|
-
assert_equal(
|
42
|
+
assert_equal(128_513, gotten)
|
38
43
|
end
|
39
44
|
end
|
40
45
|
|
@@ -52,59 +57,95 @@ describe HexaPDF::Font::TrueTypeWrapper do
|
|
52
57
|
end
|
53
58
|
|
54
59
|
describe "encode" do
|
55
|
-
it "returns the
|
56
|
-
|
60
|
+
it "returns the encoded glyph ID for fonts that are subset" do
|
61
|
+
code = @font_wrapper.encode(@font_wrapper.glyph(3))
|
62
|
+
assert_equal([1].pack('n'), code)
|
63
|
+
code = @font_wrapper.encode(@font_wrapper.glyph(10))
|
64
|
+
assert_equal([2].pack('n'), code)
|
65
|
+
end
|
57
66
|
|
67
|
+
it "returns the encoded glyph ID for fonts that are not subset" do
|
68
|
+
@font_wrapper = HexaPDF::Font::TrueTypeWrapper.new(@doc, @font, subset: false)
|
58
69
|
code = @font_wrapper.encode(@font_wrapper.glyph(3))
|
59
70
|
assert_equal([3].pack('n'), code)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
@doc.dispatch_message(:complete_objects)
|
71
|
+
code = @font_wrapper.encode(@font_wrapper.glyph(10))
|
72
|
+
assert_equal([10].pack('n'), code)
|
73
|
+
end
|
74
|
+
end
|
65
75
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
@font[:'OS/2'].
|
76
|
+
it "creates the necessary PDF dictionaries" do
|
77
|
+
@font_wrapper.encode(@font_wrapper.glyph(3))
|
78
|
+
glyph = @font_wrapper.decode_utf8('H').first
|
79
|
+
@font_wrapper.encode(glyph)
|
80
|
+
@doc.dispatch_message(:complete_objects)
|
81
|
+
|
82
|
+
dict = @font_wrapper.dict
|
83
|
+
|
84
|
+
# Checking Type 0 font dictionary
|
85
|
+
assert_equal(:Font, dict[:Type])
|
86
|
+
assert_equal(:Type0, dict[:Subtype])
|
87
|
+
assert_equal(:'Identity-H', dict[:Encoding])
|
88
|
+
assert_equal(1, dict[:DescendantFonts].length)
|
89
|
+
assert_equal(dict[:BaseFont], dict[:DescendantFonts][0][:BaseFont])
|
90
|
+
assert_equal(HexaPDF::Font::CMap.create_to_unicode_cmap([[3, ' '.ord], [glyph.id, 'H'.ord]]),
|
91
|
+
dict[:ToUnicode].stream)
|
92
|
+
assert_match(/\A[A-Z]{6}\+Ubuntu-Title\z/, dict[:BaseFont])
|
93
|
+
|
94
|
+
# Checking CIDFont dictionary
|
95
|
+
cidfont = dict[:DescendantFonts][0]
|
96
|
+
assert_equal(:Font, cidfont[:Type])
|
97
|
+
assert_equal(:CIDFontType2, cidfont[:Subtype])
|
98
|
+
assert_equal({Registry: "Adobe", Ordering: "Identity", Supplement: 0}, cidfont[:CIDSystemInfo])
|
99
|
+
assert_equal(:Identity, cidfont[:CIDToGIDMap])
|
100
|
+
assert_equal(@font_wrapper.glyph(3).width, cidfont[:DW])
|
101
|
+
assert_equal([glyph.id, [glyph.width]], cidfont[:W])
|
102
|
+
|
103
|
+
# Checking font descriptor
|
104
|
+
fd = cidfont[:FontDescriptor]
|
105
|
+
assert_equal(dict[:BaseFont], fd[:FontName])
|
106
|
+
assert(fd.flagged?(:symbolic))
|
107
|
+
assert(fd.key?(:FontFile2))
|
108
|
+
assert(fd.validate)
|
109
|
+
|
110
|
+
# Two special cases for determining cap height and x-height
|
111
|
+
@cmap.stub(:[], nil) do
|
112
|
+
@font[:'OS/2'].typo_ascender = 1000
|
103
113
|
font_wrapper = HexaPDF::Font::TrueTypeWrapper.new(@doc, @font)
|
104
114
|
font_wrapper.encode(glyph)
|
105
115
|
fd = font_wrapper.dict[:DescendantFonts][0][:FontDescriptor]
|
106
|
-
assert_equal(
|
116
|
+
assert_equal(800, fd[:CapHeight])
|
107
117
|
assert_equal(500, fd[:XHeight])
|
108
118
|
end
|
119
|
+
|
120
|
+
@font[:'OS/2'].version = 2
|
121
|
+
@font[:'OS/2'].x_height = 500 * @font[:head].units_per_em / 1000
|
122
|
+
@font[:'OS/2'].cap_height = 1000 * @font[:head].units_per_em / 1000
|
123
|
+
font_wrapper = HexaPDF::Font::TrueTypeWrapper.new(@doc, @font)
|
124
|
+
font_wrapper.encode(glyph)
|
125
|
+
fd = font_wrapper.dict[:DescendantFonts][0][:FontDescriptor]
|
126
|
+
assert_equal(1000, fd[:CapHeight])
|
127
|
+
assert_equal(500, fd[:XHeight])
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "font file embedding" do
|
131
|
+
it "embeds subset fonts" do
|
132
|
+
@font_wrapper.encode(@font_wrapper.glyph(10))
|
133
|
+
@doc.dispatch_message(:complete_objects)
|
134
|
+
|
135
|
+
font_data = @font_wrapper.dict[:DescendantFonts][0][:FontDescriptor][:FontFile2].stream
|
136
|
+
font = HexaPDF::Font::TrueType::Font.new(StringIO.new(font_data))
|
137
|
+
assert_equal(@font[:glyf][0].raw_data, font[:glyf][0].raw_data)
|
138
|
+
assert_equal(@font[:glyf][10].raw_data, font[:glyf][1].raw_data)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "embeds full fonts" do
|
142
|
+
@font_wrapper = HexaPDF::Font::TrueTypeWrapper.new(@doc, @font, subset: false)
|
143
|
+
@doc.dispatch_message(:complete_objects)
|
144
|
+
|
145
|
+
assert_equal(File.size(@font_file),
|
146
|
+
@font_wrapper.dict[:DescendantFonts][0][:FontDescriptor][:FontFile2][:Length1])
|
147
|
+
assert_equal(File.binread(@font_file),
|
148
|
+
@font_wrapper.dict[:DescendantFonts][0][:FontDescriptor][:FontFile2].stream)
|
149
|
+
end
|
109
150
|
end
|
110
151
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'stringio'
|
5
|
+
require 'hexapdf/font/true_type'
|
6
|
+
|
7
|
+
describe HexaPDF::Font::TrueType::Subsetter do
|
8
|
+
before do
|
9
|
+
font_file = File.join(TEST_DATA_DIR, "fonts", "Ubuntu-Title.ttf")
|
10
|
+
@font = HexaPDF::Font::TrueType::Font.new(File.open(font_file))
|
11
|
+
@subsetter = HexaPDF::Font::TrueType::Subsetter.new(@font)
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
@font.io.close
|
16
|
+
end
|
17
|
+
|
18
|
+
it "adds glyphs to the subset" do
|
19
|
+
assert_equal(1, @subsetter.use_glyph(5))
|
20
|
+
assert_equal(2, @subsetter.use_glyph(6))
|
21
|
+
assert_equal(1, @subsetter.use_glyph(5))
|
22
|
+
end
|
23
|
+
|
24
|
+
it "creates the subset font file" do
|
25
|
+
gid = @font[:cmap].preferred_table[0x41]
|
26
|
+
@subsetter.use_glyph(gid)
|
27
|
+
subset = HexaPDF::Font::TrueType::Font.new(StringIO.new(@subsetter.build_font))
|
28
|
+
|
29
|
+
assert(subset[:head])
|
30
|
+
assert(subset[:head].checksum_valid?)
|
31
|
+
assert(subset[:hhea])
|
32
|
+
assert(subset[:hhea].checksum_valid?)
|
33
|
+
assert(subset[:glyf])
|
34
|
+
assert(subset[:glyf].checksum_valid?)
|
35
|
+
assert(subset[:loca])
|
36
|
+
assert(subset[:loca].checksum_valid?)
|
37
|
+
assert(subset[:maxp])
|
38
|
+
assert(subset[:maxp].checksum_valid?)
|
39
|
+
assert(subset[:hmtx])
|
40
|
+
assert(subset[:hmtx].checksum_valid?)
|
41
|
+
|
42
|
+
assert(Time.now - subset[:head].modified < 10)
|
43
|
+
assert_equal(2, subset[:maxp].num_glyphs)
|
44
|
+
assert_equal(2, subset[:hhea].num_of_long_hor_metrics)
|
45
|
+
assert_equal(3, subset[:loca].offsets.length)
|
46
|
+
|
47
|
+
assert_equal(subset[:hmtx][0], @font[:hmtx][0])
|
48
|
+
assert_equal(subset[:hmtx][1], @font[:hmtx][gid])
|
49
|
+
|
50
|
+
assert_equal(subset[:glyf][1].raw_data, @font[:glyf][gid].raw_data)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "correctly subsets compound glyphs" do
|
54
|
+
font_file = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
|
55
|
+
skip unless File.exist?(font_file)
|
56
|
+
|
57
|
+
begin
|
58
|
+
@font = HexaPDF::Font::TrueType::Font.new(File.open(font_file))
|
59
|
+
@subsetter = HexaPDF::Font::TrueType::Subsetter.new(@font)
|
60
|
+
|
61
|
+
@subsetter.use_glyph(@font[:cmap].preferred_table['À'.ord])
|
62
|
+
subset = HexaPDF::Font::TrueType::Font.new(StringIO.new(@subsetter.build_font))
|
63
|
+
|
64
|
+
assert_equal(4, subset[:maxp].num_glyphs)
|
65
|
+
assert_equal([2, 3], subset[:glyf][1].components)
|
66
|
+
ensure
|
67
|
+
@font.io.close
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -29,4 +29,20 @@ describe HexaPDF::Font::TrueType::Table do
|
|
29
29
|
assert(table.checksum_valid?)
|
30
30
|
end
|
31
31
|
end
|
32
|
+
|
33
|
+
describe "read_fixed" do
|
34
|
+
it "works for unsigned values" do
|
35
|
+
@file.io.string = [1, 20480].pack('nn')
|
36
|
+
@entry.length = @file.io.string.length
|
37
|
+
table = TestHelper::TrueTypeTestTable.new(@file, @entry)
|
38
|
+
assert_equal(1 + Rational(20480, 65536), table.send(:read_fixed))
|
39
|
+
end
|
40
|
+
|
41
|
+
it "works for signed values" do
|
42
|
+
@file.io.string = [-1, 20480].pack('nn')
|
43
|
+
@entry.length = @file.io.string.length
|
44
|
+
table = TestHelper::TrueTypeTestTable.new(@file, @entry)
|
45
|
+
assert_equal(-1 + Rational(20480, 65536), table.send(:read_fixed))
|
46
|
+
end
|
47
|
+
end
|
32
48
|
end
|
@@ -17,6 +17,13 @@ describe HexaPDF::FontLoader::FromConfiguration do
|
|
17
17
|
assert_equal("Ubuntu-Title", wrapper.wrapped_font.font_name)
|
18
18
|
end
|
19
19
|
|
20
|
+
it "passes the subset value to the wrapper" do
|
21
|
+
wrapper = @klass.call(@doc, "font")
|
22
|
+
assert(wrapper.subset?)
|
23
|
+
wrapper = @klass.call(@doc, "font", subset: false)
|
24
|
+
refute(wrapper.subset?)
|
25
|
+
end
|
26
|
+
|
20
27
|
it "fails if the font file cannot be read" do
|
21
28
|
@doc.config['font.map']['font'][:none] << "unknown"
|
22
29
|
assert_raises(HexaPDF::Error) { @klass.call(@doc, "font") }
|
@@ -392,7 +392,7 @@ EOF
|
|
392
392
|
objs = [[10, 20, 30], [200, nil]]
|
393
393
|
data = @io_doc.revisions.map.with_index {|rev, i| objs[i].map {|o| [o, rev]}}.reverse.flatten
|
394
394
|
@io_doc.each(current: false) do |obj, rev|
|
395
|
-
|
395
|
+
assert(data.shift == obj.value)
|
396
396
|
assert_equal(data.shift, rev)
|
397
397
|
end
|
398
398
|
end
|
data/test/hexapdf/test_object.rb
CHANGED
@@ -9,7 +9,7 @@ describe HexaPDF::Object do
|
|
9
9
|
it "handles not-duplicatable classes" do
|
10
10
|
assert_equal(5, HexaPDF::Object.deep_copy(5))
|
11
11
|
assert_equal(5.5, HexaPDF::Object.deep_copy(5.5))
|
12
|
-
|
12
|
+
assert_nil(HexaPDF::Object.deep_copy(nil))
|
13
13
|
assert_equal(true, HexaPDF::Object.deep_copy(true))
|
14
14
|
assert_equal(false, HexaPDF::Object.deep_copy(false))
|
15
15
|
assert_equal(:Name, HexaPDF::Object.deep_copy(:Name))
|
@@ -28,17 +28,42 @@ startxref
|
|
28
28
|
47
|
29
29
|
%%EOF
|
30
30
|
|
31
|
+
2 0 obj
|
32
|
+
300
|
33
|
+
endobj
|
34
|
+
|
35
|
+
3 0 obj
|
36
|
+
<< /Type /XRef /Size 4 /Index [2 1] /W [1 1 1] /Filter /ASCIIHexDecode /Length 6
|
37
|
+
>>stream
|
38
|
+
019E00
|
39
|
+
endstream
|
40
|
+
endobj
|
41
|
+
|
31
42
|
2 0 obj
|
32
43
|
200
|
33
44
|
endobj
|
34
45
|
|
46
|
+
xref
|
47
|
+
2 2
|
48
|
+
0000000301 00000 n
|
49
|
+
0000000178 00000 n
|
50
|
+
trailer
|
51
|
+
<< /Size 4 /Prev 47 >>
|
52
|
+
startxref
|
53
|
+
321
|
54
|
+
%%EOF
|
55
|
+
|
56
|
+
2 0 obj
|
57
|
+
400
|
58
|
+
endobj
|
59
|
+
|
35
60
|
xref
|
36
61
|
2 1
|
37
|
-
|
62
|
+
0000000422 00000 n
|
38
63
|
trailer
|
39
|
-
<< /Size
|
64
|
+
<< /Size 4 /Prev 321 /XRefStm 178 >>
|
40
65
|
startxref
|
41
|
-
|
66
|
+
442
|
42
67
|
%%EOF
|
43
68
|
EOF
|
44
69
|
@doc = HexaPDF::Document.new(io: @io)
|
@@ -48,7 +73,7 @@ EOF
|
|
48
73
|
describe "add" do
|
49
74
|
it "adds an empty revision as the current revision" do
|
50
75
|
rev = @revisions.add
|
51
|
-
assert_equal({Size:
|
76
|
+
assert_equal({Size: 4}, rev.trailer.value)
|
52
77
|
assert_equal(rev, @revisions.current)
|
53
78
|
end
|
54
79
|
end
|
@@ -74,27 +99,28 @@ EOF
|
|
74
99
|
describe "merge" do
|
75
100
|
it "does nothing when only one revision is specified" do
|
76
101
|
@revisions.merge(1..1)
|
77
|
-
assert_equal(
|
102
|
+
assert_equal(3, @revisions.each.to_a.size)
|
78
103
|
end
|
79
104
|
|
80
105
|
it "merges the higher into the the lower revision" do
|
81
106
|
@revisions.merge
|
82
107
|
assert_equal(1, @revisions.each.to_a.size)
|
83
|
-
assert_equal([10,
|
108
|
+
assert_equal([10, 400, @doc.object(3).value], @revisions.current.each.to_a.sort.map(&:value))
|
84
109
|
end
|
85
110
|
|
86
111
|
it "handles objects correctly that are in multiple revisions" do
|
87
112
|
@revisions.current.add(@revisions[0].object(1))
|
88
113
|
@revisions.merge
|
89
114
|
assert_equal(1, @revisions.each.to_a.size)
|
90
|
-
assert_equal([10,
|
115
|
+
assert_equal([10, 400, @doc.object(3).value], @revisions.current.each.to_a.sort.map(&:value))
|
91
116
|
end
|
92
117
|
end
|
93
118
|
|
94
119
|
describe "initialize" do
|
95
120
|
it "automatically loads all revisions from the underlying IO object" do
|
96
121
|
assert_equal(20, @revisions.revision(0).object(2).value)
|
97
|
-
assert_equal(
|
122
|
+
assert_equal(300, @revisions[1].object(2).value)
|
123
|
+
assert_equal(400, @revisions[2].object(2).value)
|
98
124
|
end
|
99
125
|
end
|
100
126
|
end
|