hexapdf 1.0.1 → 1.0.2
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 +14 -0
- data/lib/hexapdf/configuration.rb +1 -0
- data/lib/hexapdf/font/true_type/subsetter.rb +2 -15
- data/lib/hexapdf/font/true_type/table.rb +6 -1
- data/lib/hexapdf/font/true_type_wrapper.rb +10 -1
- data/lib/hexapdf/type/cid_font.rb +1 -1
- data/lib/hexapdf/type/cmap.rb +58 -0
- data/lib/hexapdf/type.rb +1 -0
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/font/test_true_type_wrapper.rb +5 -0
- data/test/hexapdf/font/true_type/test_subsetter.rb +0 -10
- data/test/hexapdf/font/true_type/test_table.rb +12 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 44eb3afec42bc0c5e0645c0ff6eb48f211083694866fb7c355a0b4ca3e3ad24a
|
4
|
+
data.tar.gz: 864792c029e975b0d8167d80326815ea6a7ebff90bc360c4d550c8a2d4a28003
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19d415762cb49abfaf31df0d6dc8455c5a6a8b1eee40f18cc4d56b7a18e4d9e9aded8d5826a4f5a265bbc639d61f5a2fe081b1e672b626984d4be719115f4c9a
|
7
|
+
data.tar.gz: 6c8d31294566e9c408cb0fe8512ca4898d583edebe750191fda6d42fcb0a6cb44d83de90359abcac6cca1cf7b47f38e3515b5c94246456b485091d3d72c0be5c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## 1.0.1 - 2024-11-05
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* [HexaPDF::Type::CMap] for representing CMap streams
|
6
|
+
|
7
|
+
### Fixed
|
8
|
+
|
9
|
+
* Checksum calculation for TrueType tables
|
10
|
+
* Automatic wrapping of dictionary entry /CIDToGIDMap for CID fonts
|
11
|
+
* Performance regression when encoding char codes for TrueType fonts
|
12
|
+
* PDF/A validation regression for PDFs using TrueType fonts
|
13
|
+
|
14
|
+
|
1
15
|
## 1.0.1 - 2024-11-04
|
2
16
|
|
3
17
|
### Changed
|
@@ -722,6 +722,7 @@ module HexaPDF
|
|
722
722
|
OutputIntent: 'HexaPDF::Type::OutputIntent',
|
723
723
|
XXDestOutputProfileRef: 'HexaPDF::Type::OutputIntent::DestOutputProfileRef',
|
724
724
|
ExData: 'HexaPDF::Type::Annotations::MarkupAnnotation::ExData',
|
725
|
+
CMap: 'HexaPDF::Type::CMap',
|
725
726
|
},
|
726
727
|
'object.subtype_map' => {
|
727
728
|
nil => {
|
@@ -63,16 +63,6 @@ module HexaPDF
|
|
63
63
|
def use_glyph(glyph_id)
|
64
64
|
return @glyph_map[glyph_id] if @glyph_map.key?(glyph_id)
|
65
65
|
@last_id += 1
|
66
|
-
# Handle codes for ASCII characters \r (13), (, ) (40, 41) and \ (92) specially so that
|
67
|
-
# they never appear in the output (PDF serialization would need to escape them)
|
68
|
-
if @last_id == 13 || @last_id == 40 || @last_id == 92
|
69
|
-
@glyph_map[:"s#{@last_id}"] = @last_id
|
70
|
-
if @last_id == 40
|
71
|
-
@last_id += 1
|
72
|
-
@glyph_map[:"s#{@last_id}"] = @last_id
|
73
|
-
end
|
74
|
-
@last_id += 1
|
75
|
-
end
|
76
66
|
@glyph_map[glyph_id] = @last_id
|
77
67
|
end
|
78
68
|
|
@@ -117,7 +107,7 @@ module HexaPDF
|
|
117
107
|
locations = []
|
118
108
|
|
119
109
|
@glyph_map.each_key do |old_gid|
|
120
|
-
glyph = orig_glyf[old_gid
|
110
|
+
glyph = orig_glyf[old_gid]
|
121
111
|
locations << table.size
|
122
112
|
data = glyph.raw_data
|
123
113
|
if glyph.compound?
|
@@ -176,10 +166,7 @@ module HexaPDF
|
|
176
166
|
# Adds the components of compound glyphs to the subset.
|
177
167
|
def add_glyph_components
|
178
168
|
glyf = @font[:glyf]
|
179
|
-
@glyph_map.keys.each
|
180
|
-
next if gid.kind_of?(Symbol)
|
181
|
-
glyf[gid].components&.each {|cgid| use_glyph(cgid) }
|
182
|
-
end
|
169
|
+
@glyph_map.keys.each {|gid| glyf[gid].components&.each {|cgid| use_glyph(cgid) } }
|
183
170
|
end
|
184
171
|
|
185
172
|
end
|
@@ -63,7 +63,12 @@ module HexaPDF
|
|
63
63
|
|
64
64
|
# Calculates the checksum for the given data.
|
65
65
|
def self.calculate_checksum(data)
|
66
|
-
|
66
|
+
checksum = 0
|
67
|
+
if (remainder_length = data.length % 4) != 0
|
68
|
+
checksum = (data[-remainder_length, remainder_length] << "\0" * (4 - remainder_length)).
|
69
|
+
unpack1('N')
|
70
|
+
end
|
71
|
+
checksum + data.unpack('N*').inject(0) {|sum, long| sum + long } % 2**32
|
67
72
|
end
|
68
73
|
|
69
74
|
# The TrueType font object associated with this table.
|
@@ -239,6 +239,11 @@ module HexaPDF
|
|
239
239
|
raise HexaPDF::MissingGlyphError.new(glyph) if glyph.kind_of?(InvalidGlyph)
|
240
240
|
@subsetter.use_glyph(glyph.id) if @subsetter
|
241
241
|
@last_char_code += 1
|
242
|
+
# Handle codes for ASCII characters \r (13), (, ) (40, 41) and \ (92) specially so that
|
243
|
+
# they never appear in the output (PDF serialization would need to escape them)
|
244
|
+
if @last_char_code == 13 || @last_char_code == 40 || @last_char_code == 92
|
245
|
+
@last_char_code += (@last_char_code == 40 ? 2 : 1)
|
246
|
+
end
|
242
247
|
[[@last_char_code].pack('n'), @last_char_code]
|
243
248
|
end)[0]
|
244
249
|
end
|
@@ -376,7 +381,11 @@ module HexaPDF
|
|
376
381
|
dict[:Encoding] = :'Identity-H'
|
377
382
|
else
|
378
383
|
stream = HexaPDF::StreamData.new { HexaPDF::Font::CMap.create_cid_cmap(mapping) }
|
379
|
-
stream_obj = document.add({
|
384
|
+
stream_obj = document.add({Type: :CMap,
|
385
|
+
CMapName: :Custom,
|
386
|
+
CIDSystemInfo: {Registry: "Adobe", Ordering: "Identity",
|
387
|
+
Supplement: 0},
|
388
|
+
}, stream: stream)
|
380
389
|
stream_obj.set_filter(:FlateDecode)
|
381
390
|
dict[:Encoding] = stream_obj
|
382
391
|
end
|
@@ -70,7 +70,7 @@ module HexaPDF
|
|
70
70
|
define_field :W, type: PDFArray
|
71
71
|
define_field :DW2, type: PDFArray, default: [880, -1100]
|
72
72
|
define_field :W2, type: PDFArray
|
73
|
-
define_field :CIDToGIDMap, type: [
|
73
|
+
define_field :CIDToGIDMap, type: [Stream, Symbol]
|
74
74
|
|
75
75
|
# Returns the unscaled width of the given CID in glyph units, or 0 if the width for the CID is
|
76
76
|
# missing.
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- encoding: utf-8; frozen_string_literal: true -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# This file is part of HexaPDF.
|
5
|
+
#
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
+
# Copyright (C) 2014-2024 Thomas Leitner
|
8
|
+
#
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
16
|
+
#
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
20
|
+
# License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
24
|
+
#
|
25
|
+
# The interactive user interfaces in modified source and object code
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
28
|
+
#
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
31
|
+
# is created or manipulated using HexaPDF.
|
32
|
+
#
|
33
|
+
# If the GNU Affero General Public License doesn't fit your need,
|
34
|
+
# commercial licenses are available at <https://gettalong.at/hexapdf/>.
|
35
|
+
#++
|
36
|
+
|
37
|
+
require 'hexapdf/stream'
|
38
|
+
|
39
|
+
module HexaPDF
|
40
|
+
module Type
|
41
|
+
|
42
|
+
# Represents an embedded CMap file.
|
43
|
+
#
|
44
|
+
# See: PDF2.0 s9.7.5.3
|
45
|
+
class CMap < Stream
|
46
|
+
|
47
|
+
define_type :CMap
|
48
|
+
|
49
|
+
define_field :Type, type: Symbol, required: true, default: type
|
50
|
+
define_field :CMapName, type: Symbol, required: true
|
51
|
+
define_field :CIDSystemInfo, type: :XXCIDSystemInfo, required: true
|
52
|
+
define_field :WMode, type: Integer
|
53
|
+
define_field :UseCMap, type: [Stream, Symbol]
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
data/lib/hexapdf/type.rb
CHANGED
@@ -82,6 +82,7 @@ module HexaPDF
|
|
82
82
|
autoload(:OptionalContentConfiguration, 'hexapdf/type/optional_content_configuration')
|
83
83
|
autoload(:Metadata, 'hexapdf/type/metadata')
|
84
84
|
autoload(:OutputIntent, 'hexapdf/type/output_intent')
|
85
|
+
autoload(:CMap, 'hexapdf/type/cmap')
|
85
86
|
|
86
87
|
end
|
87
88
|
|
data/lib/hexapdf/version.rb
CHANGED
@@ -119,6 +119,11 @@ describe HexaPDF::Font::TrueTypeWrapper do
|
|
119
119
|
assert_equal([3].pack('n'), code)
|
120
120
|
end
|
121
121
|
|
122
|
+
it "doesn't use char codes 13, 40, 41 and 92 because they would need to be escaped" do
|
123
|
+
codes = 1.upto(93).map {|i| @font_wrapper.encode(@font_wrapper.glyph(i)) }.join
|
124
|
+
assert_equal([1..12, 14..39, 42..91, 93..97].flat_map(&:to_a).pack('n*'), codes)
|
125
|
+
end
|
126
|
+
|
122
127
|
it "raises an error if an InvalidGlyph is encoded" do
|
123
128
|
exp = assert_raises(HexaPDF::MissingGlyphError) do
|
124
129
|
@font_wrapper.encode(@font_wrapper.decode_utf8("ö").first)
|
@@ -27,16 +27,6 @@ describe HexaPDF::Font::TrueType::Subsetter do
|
|
27
27
|
assert_equal(value, @subsetter.subset_glyph_id(5))
|
28
28
|
end
|
29
29
|
|
30
|
-
it "doesn't use certain subset glyph IDs for performance reasons" do
|
31
|
-
1.upto(93) {|i| @subsetter.use_glyph(i) }
|
32
|
-
# glyph 0, 93 used glyph, 4 special glyphs
|
33
|
-
assert_equal(1 + 93 + 4, @subsetter.instance_variable_get(:@glyph_map).size)
|
34
|
-
1.upto(12) {|i| assert_equal(i, @subsetter.subset_glyph_id(i), "id=#{i}") }
|
35
|
-
13.upto(38) {|i| assert_equal(i + 1, @subsetter.subset_glyph_id(i), "id=#{i}") }
|
36
|
-
39.upto(88) {|i| assert_equal(i + 3, @subsetter.subset_glyph_id(i), "id=#{i}") }
|
37
|
-
89.upto(93) {|i| assert_equal(i + 4, @subsetter.subset_glyph_id(i), "id=#{i}") }
|
38
|
-
end
|
39
|
-
|
40
30
|
it "creates the subset font file" do
|
41
31
|
gid = @font[:cmap].preferred_table[0x41]
|
42
32
|
@subsetter.use_glyph(gid)
|
@@ -13,6 +13,18 @@ describe HexaPDF::Font::TrueType::Table do
|
|
13
13
|
@entry = HexaPDF::Font::TrueType::Table::Directory::Entry.new('tagg', 0, 0, @file.io.string.length)
|
14
14
|
end
|
15
15
|
|
16
|
+
describe "self.calculate_checksum" do
|
17
|
+
it "works for data with a length divisible by four" do
|
18
|
+
klass = HexaPDF::Font::TrueType::Table
|
19
|
+
assert_equal(256, klass.calculate_checksum("\x00\x00\x00\x01\x00\x00\x00\xFF"))
|
20
|
+
end
|
21
|
+
|
22
|
+
it "works for data with a length not divisible by four" do
|
23
|
+
klass = HexaPDF::Font::TrueType::Table
|
24
|
+
assert_equal(512, klass.calculate_checksum("\x00\x00\x00\x01\x00\x00\x00\xFF\x00\x00\x01"))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
16
28
|
describe "initialize" do
|
17
29
|
it "reads the data from the associated file" do
|
18
30
|
table = TrueTypeTestTable.new(@file, @entry)
|
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: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Leitner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-11-
|
11
|
+
date: 2024-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cmdparse
|
@@ -500,6 +500,7 @@ files:
|
|
500
500
|
- lib/hexapdf/type/annotations/widget.rb
|
501
501
|
- lib/hexapdf/type/catalog.rb
|
502
502
|
- lib/hexapdf/type/cid_font.rb
|
503
|
+
- lib/hexapdf/type/cmap.rb
|
503
504
|
- lib/hexapdf/type/embedded_file.rb
|
504
505
|
- lib/hexapdf/type/file_specification.rb
|
505
506
|
- lib/hexapdf/type/font.rb
|