hexapdf 0.3.0 → 0.4.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 +68 -0
- data/CONTRIBUTERS +1 -1
- data/README.md +35 -4
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/data/hexapdf/cmap/83pv-RKSJ-H +314 -0
- data/data/hexapdf/cmap/90ms-RKSJ-H +259 -0
- data/data/hexapdf/cmap/90ms-RKSJ-V +156 -0
- data/data/hexapdf/cmap/90msp-RKSJ-H +257 -0
- data/data/hexapdf/cmap/90msp-RKSJ-V +155 -0
- data/data/hexapdf/cmap/90pv-RKSJ-H +355 -0
- data/data/hexapdf/cmap/Add-RKSJ-H +738 -0
- data/data/hexapdf/cmap/Add-RKSJ-V +135 -0
- data/data/hexapdf/cmap/Adobe-CNS1-UCS2 +18209 -0
- data/data/hexapdf/cmap/Adobe-GB1-UCS2 +14267 -0
- data/data/hexapdf/cmap/Adobe-Japan1-UCS2 +19159 -0
- data/data/hexapdf/cmap/Adobe-Korea1-UCS2 +9267 -0
- data/data/hexapdf/cmap/B5pc-H +337 -0
- data/data/hexapdf/cmap/B5pc-V +90 -0
- data/data/hexapdf/cmap/CNS-EUC-H +490 -0
- data/data/hexapdf/cmap/CNS-EUC-V +538 -0
- data/data/hexapdf/cmap/ETen-B5-H +343 -0
- data/data/hexapdf/cmap/ETen-B5-V +91 -0
- data/data/hexapdf/cmap/ETenms-B5-H +79 -0
- data/data/hexapdf/cmap/ETenms-B5-V +99 -0
- data/data/hexapdf/cmap/EUC-H +207 -0
- data/data/hexapdf/cmap/EUC-V +105 -0
- data/data/hexapdf/cmap/Ext-RKSJ-H +768 -0
- data/data/hexapdf/cmap/Ext-RKSJ-V +117 -0
- data/data/hexapdf/cmap/GB-EUC-H +173 -0
- data/data/hexapdf/cmap/GB-EUC-V +98 -0
- data/data/hexapdf/cmap/GBK-EUC-H +4273 -0
- data/data/hexapdf/cmap/GBK-EUC-V +97 -0
- data/data/hexapdf/cmap/GBK2K-H +5325 -0
- data/data/hexapdf/cmap/GBK2K-V +118 -0
- data/data/hexapdf/cmap/GBKp-EUC-H +4272 -0
- data/data/hexapdf/cmap/GBKp-EUC-V +97 -0
- data/data/hexapdf/cmap/GBpc-EUC-H +175 -0
- data/data/hexapdf/cmap/GBpc-EUC-V +98 -0
- data/data/hexapdf/cmap/H +200 -0
- data/data/hexapdf/cmap/HKscs-B5-H +1331 -0
- data/data/hexapdf/cmap/HKscs-B5-V +90 -0
- data/data/hexapdf/cmap/Identity-H +339 -0
- data/data/hexapdf/cmap/Identity-V +73 -0
- data/data/hexapdf/cmap/KSC-EUC-H +562 -0
- data/data/hexapdf/cmap/KSC-EUC-V +94 -0
- data/data/hexapdf/cmap/KSCms-UHC-H +776 -0
- data/data/hexapdf/cmap/KSCms-UHC-HW-H +775 -0
- data/data/hexapdf/cmap/KSCms-UHC-HW-V +93 -0
- data/data/hexapdf/cmap/KSCms-UHC-V +94 -0
- data/data/hexapdf/cmap/KSCpc-EUC-H +608 -0
- data/data/hexapdf/cmap/LICENSE.txt +26 -0
- data/data/hexapdf/cmap/README.txt +9 -0
- data/data/hexapdf/cmap/UniCNS-UCS2-H +16992 -0
- data/data/hexapdf/cmap/UniCNS-UCS2-V +90 -0
- data/data/hexapdf/cmap/UniCNS-UTF16-H +19117 -0
- data/data/hexapdf/cmap/UniCNS-UTF16-V +94 -0
- data/data/hexapdf/cmap/UniGB-UCS2-H +14321 -0
- data/data/hexapdf/cmap/UniGB-UCS2-V +101 -0
- data/data/hexapdf/cmap/UniGB-UTF16-H +14381 -0
- data/data/hexapdf/cmap/UniGB-UTF16-V +104 -0
- data/data/hexapdf/cmap/UniJIS-UCS2-H +8870 -0
- data/data/hexapdf/cmap/UniJIS-UCS2-HW-H +81 -0
- data/data/hexapdf/cmap/UniJIS-UCS2-HW-V +279 -0
- data/data/hexapdf/cmap/UniJIS-UCS2-V +275 -0
- data/data/hexapdf/cmap/UniJIS-UTF16-H +14450 -0
- data/data/hexapdf/cmap/UniJIS-UTF16-V +299 -0
- data/data/hexapdf/cmap/UniKS-UCS2-H +8725 -0
- data/data/hexapdf/cmap/UniKS-UCS2-V +95 -0
- data/data/hexapdf/cmap/UniKS-UTF16-H +8895 -0
- data/data/hexapdf/cmap/UniKS-UTF16-V +99 -0
- data/data/hexapdf/cmap/V +105 -0
- data/examples/arc.rb +3 -3
- data/examples/merging.rb +4 -1
- data/examples/optimizing.rb +3 -0
- data/examples/show_char_bboxes.rb +2 -2
- data/examples/truetype.rb +2 -2
- data/lib/hexapdf/cli.rb +40 -1
- data/lib/hexapdf/cli/batch.rb +72 -0
- data/lib/hexapdf/cli/command.rb +112 -15
- data/lib/hexapdf/cli/files.rb +2 -2
- data/lib/hexapdf/cli/images.rb +14 -6
- data/lib/hexapdf/cli/info.rb +6 -8
- data/lib/hexapdf/cli/inspect.rb +5 -8
- data/lib/hexapdf/cli/merge.rb +13 -20
- data/lib/hexapdf/cli/modify.rb +4 -7
- data/lib/hexapdf/cli/optimize.rb +2 -5
- data/lib/hexapdf/configuration.rb +32 -3
- data/lib/hexapdf/content/canvas.rb +130 -37
- data/lib/hexapdf/content/parser.rb +40 -6
- data/lib/hexapdf/content/processor.rb +4 -4
- data/lib/hexapdf/document.rb +40 -10
- data/lib/hexapdf/document/fonts.rb +1 -0
- data/lib/hexapdf/encryption/security_handler.rb +8 -12
- data/lib/hexapdf/filter/flate_decode.rb +25 -2
- data/lib/hexapdf/font/cmap.rb +124 -8
- data/lib/hexapdf/font/cmap/parser.rb +65 -15
- data/lib/hexapdf/font/encoding/base.rb +2 -2
- data/lib/hexapdf/font/encoding/glyph_list.rb +2 -4
- data/lib/hexapdf/font/true_type.rb +1 -0
- data/lib/hexapdf/font/true_type/builder.rb +75 -0
- data/lib/hexapdf/font/true_type/optimizer.rb +65 -0
- data/lib/hexapdf/font/true_type/subsetter.rb +9 -22
- data/lib/hexapdf/font/true_type_wrapper.rb +9 -21
- data/lib/hexapdf/font_loader.rb +1 -1
- data/lib/hexapdf/importer.rb +1 -1
- data/lib/hexapdf/serializer.rb +5 -3
- data/lib/hexapdf/type.rb +2 -0
- data/lib/hexapdf/type/cid_font.rb +120 -0
- data/lib/hexapdf/type/font.rb +32 -12
- data/lib/hexapdf/type/font_simple.rb +34 -42
- data/lib/hexapdf/type/font_type0.rb +148 -0
- data/lib/hexapdf/type/form.rb +4 -4
- data/lib/hexapdf/type/page.rb +12 -11
- data/lib/hexapdf/type/resources.rb +14 -0
- data/lib/hexapdf/utils/graphics_helpers.rb +77 -0
- data/lib/hexapdf/version.rb +1 -1
- data/man/man1/hexapdf.1 +43 -1
- data/test/hexapdf/content/test_canvas.rb +76 -0
- data/test/hexapdf/content/test_parser.rb +20 -1
- data/test/hexapdf/content/test_processor.rb +11 -7
- data/test/hexapdf/document/test_fonts.rb +3 -1
- data/test/hexapdf/font/cmap/test_parser.rb +42 -7
- data/test/hexapdf/font/encoding/test_base.rb +1 -1
- data/test/hexapdf/font/encoding/test_glyph_list.rb +3 -3
- data/test/hexapdf/font/test_cmap.rb +104 -0
- data/test/hexapdf/font/test_true_type_wrapper.rb +63 -46
- data/test/hexapdf/font/true_type/test_builder.rb +37 -0
- data/test/hexapdf/font/true_type/test_optimizer.rb +27 -0
- data/test/hexapdf/font/true_type/test_subsetter.rb +6 -13
- data/test/hexapdf/test_configuration.rb +12 -7
- data/test/hexapdf/test_document.rb +24 -0
- data/test/hexapdf/test_importer.rb +9 -1
- data/test/hexapdf/test_writer.rb +2 -2
- data/test/hexapdf/type/test_cid_font.rb +61 -0
- data/test/hexapdf/type/test_font.rb +31 -4
- data/test/hexapdf/type/test_font_simple.rb +6 -21
- data/test/hexapdf/type/test_font_type0.rb +114 -0
- data/test/hexapdf/type/test_resources.rb +17 -1
- data/test/hexapdf/utils/test_graphics_helpers.rb +29 -0
- metadata +82 -3
@@ -61,8 +61,8 @@ module HexaPDF
|
|
61
61
|
@code_to_name.fetch(code, :'.notdef')
|
62
62
|
end
|
63
63
|
|
64
|
-
# Returns the Unicode value in UTF-8 for the given code, or
|
65
|
-
#
|
64
|
+
# Returns the Unicode value in UTF-8 for the given code, or +nil+ if the code cannot be
|
65
|
+
# mapped.
|
66
66
|
#
|
67
67
|
# Note that this method caches the result of the Unicode mapping and therefore should only
|
68
68
|
# be called after all codes have been defined.
|
@@ -71,8 +71,8 @@ module HexaPDF
|
|
71
71
|
load
|
72
72
|
end
|
73
73
|
|
74
|
-
# Maps the given name to a string by following the Adobe Glyph Specification.
|
75
|
-
#
|
74
|
+
# Maps the given name to a string by following the Adobe Glyph Specification. Returns +nil+
|
75
|
+
# if the name has no correct mapping.
|
76
76
|
#
|
77
77
|
# If this method is invoked when dealing with the ZapfDingbats font, the +zapf_dingbats+
|
78
78
|
# option needs to be set to +true+.
|
@@ -88,8 +88,6 @@ module HexaPDF
|
|
88
88
|
name = name.to_s
|
89
89
|
if name =~ /\Auni([0-9A-F]{4})\Z/ || name =~ /\Au([0-9A-f]{4,6})\Z/
|
90
90
|
'' << $1.hex
|
91
|
-
else
|
92
|
-
''
|
93
91
|
end
|
94
92
|
end
|
95
93
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
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-2017 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
|
+
|
34
|
+
module HexaPDF
|
35
|
+
module Font
|
36
|
+
module TrueType
|
37
|
+
|
38
|
+
# Builds a TrueType font file given a hash of TrueType tables.
|
39
|
+
module Builder
|
40
|
+
|
41
|
+
# Returns a TrueType font file representing the given TrueType tables (a hash mapping table
|
42
|
+
# names (strings) to table data).
|
43
|
+
def self.build(tables)
|
44
|
+
search_range = 2**(tables.length.bit_length - 1) * 16
|
45
|
+
entry_selector = tables.length.bit_length - 1
|
46
|
+
range_shift = tables.length * 16 - search_range
|
47
|
+
|
48
|
+
font_data = "\x0\x1\x0\x0".b + \
|
49
|
+
[tables.length, search_range, entry_selector, range_shift].pack('n4')
|
50
|
+
|
51
|
+
offset = font_data.length + tables.length * 16
|
52
|
+
checksum = Table.calculate_checksum(font_data)
|
53
|
+
|
54
|
+
# prepare head table for checksumming
|
55
|
+
tables['head'][8, 4] = "\0\0\0\0"
|
56
|
+
|
57
|
+
tables.each do |tag, data|
|
58
|
+
table_checksum = Table.calculate_checksum(data)
|
59
|
+
# tag, offset, data.length are all 32bit uint, table_checksum for header and body
|
60
|
+
checksum += tag.unpack('N').first + 2 * table_checksum + offset + data.length
|
61
|
+
font_data << [tag, table_checksum, offset, data.length].pack('a4N3')
|
62
|
+
offset += data.length
|
63
|
+
end
|
64
|
+
|
65
|
+
tables['head'][8, 4] = [0xB1B0AFBA - checksum].pack('N')
|
66
|
+
tables.each_value {|data| font_data << data}
|
67
|
+
|
68
|
+
font_data
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
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-2017 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
|
+
|
34
|
+
require 'hexapdf/font/true_type/builder'
|
35
|
+
|
36
|
+
module HexaPDF
|
37
|
+
module Font
|
38
|
+
module TrueType
|
39
|
+
|
40
|
+
# Provides methods for optimizing a TrueType font file in various ways.
|
41
|
+
module Optimizer
|
42
|
+
|
43
|
+
# Returns for the given font a TrueType font file as binary string that is optimized for use
|
44
|
+
# in a PDF (i.e. only the essential tables are retained).
|
45
|
+
def self.build_for_pdf(font)
|
46
|
+
tables = {
|
47
|
+
'head' => font[:head].raw_data,
|
48
|
+
'hhea' => font[:hhea].raw_data,
|
49
|
+
'maxp' => font[:maxp].raw_data,
|
50
|
+
'glyf' => font[:glyf].raw_data,
|
51
|
+
'loca' => font[:loca].raw_data,
|
52
|
+
'hmtx' => font[:hmtx].raw_data,
|
53
|
+
}
|
54
|
+
tables['cmap'] = font[:cmap].raw_data if font[:cmap]
|
55
|
+
tables['cvt '] = font[:"cvt "].raw_data if font[:"cvt "]
|
56
|
+
tables['fpgm'] = font[:fpgm].raw_data if font[:fpgm]
|
57
|
+
tables['prep'] = font[:prep].raw_data if font[:prep]
|
58
|
+
Builder.build(tables)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -31,6 +31,8 @@
|
|
31
31
|
# is created or manipulated using HexaPDF.
|
32
32
|
#++
|
33
33
|
|
34
|
+
require 'hexapdf/font/true_type/builder'
|
35
|
+
|
34
36
|
module HexaPDF
|
35
37
|
module Font
|
36
38
|
module TrueType
|
@@ -61,6 +63,12 @@ module HexaPDF
|
|
61
63
|
@glyph_map[glyph_id] = @last_id
|
62
64
|
end
|
63
65
|
|
66
|
+
# Returns the new subset glyph ID for the given glyph ID, or +nil+ if the glyph isn't
|
67
|
+
# subset.
|
68
|
+
def subset_glyph_id(glyph_id)
|
69
|
+
@glyph_map[glyph_id]
|
70
|
+
end
|
71
|
+
|
64
72
|
# Builds the subset font file and returns it as a binary string.
|
65
73
|
def build_font
|
66
74
|
glyf, locations = build_glyf_table
|
@@ -82,28 +90,7 @@ module HexaPDF
|
|
82
90
|
tables['fpgm'] = @font[:fpgm].raw_data if @font[:fpgm]
|
83
91
|
tables['prep'] = @font[:prep].raw_data if @font[:prep]
|
84
92
|
|
85
|
-
|
86
|
-
entry_selector = tables.length.bit_length - 1
|
87
|
-
range_shift = tables.length * 16 - search_range
|
88
|
-
|
89
|
-
font_data = "\x0\x1\x0\x0".b + \
|
90
|
-
[tables.length, search_range, entry_selector, range_shift].pack('n4')
|
91
|
-
|
92
|
-
offset = font_data.length + tables.length * 16
|
93
|
-
checksum = Table.calculate_checksum(font_data)
|
94
|
-
|
95
|
-
tables.each do |tag, data|
|
96
|
-
table_checksum = Table.calculate_checksum(data)
|
97
|
-
# tag, offset, data.length are all 32bit uint, table_checksum for header and body
|
98
|
-
checksum += tag.unpack('N').first + 2 * table_checksum + offset + data.length
|
99
|
-
font_data << [tag, table_checksum, offset, data.length].pack('a4N3')
|
100
|
-
offset += data.length
|
101
|
-
end
|
102
|
-
|
103
|
-
head[8, 4] = [0xB1B0AFBA - checksum].pack('N')
|
104
|
-
tables.each_value {|data| font_data << data}
|
105
|
-
|
106
|
-
font_data
|
93
|
+
Builder.build(tables)
|
107
94
|
end
|
108
95
|
|
109
96
|
private
|
@@ -247,34 +247,22 @@ module HexaPDF
|
|
247
247
|
|
248
248
|
# Adds the /DW and /W fields to the CIDFont dictionary.
|
249
249
|
def complete_width_information
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
cid_font[:W] = widths = []
|
256
|
-
last_id = -10
|
257
|
-
cur_widths = nil
|
258
|
-
glyphs.each do |glyph|
|
259
|
-
gid = glyph.id
|
260
|
-
if last_id + 1 != gid
|
261
|
-
cur_widths = []
|
262
|
-
widths << gid << cur_widths
|
263
|
-
end
|
264
|
-
cur_widths << glyph.width
|
265
|
-
last_id = gid
|
266
|
-
end
|
267
|
-
end
|
250
|
+
default_width = glyph(3).width.to_i
|
251
|
+
widths = @encoded_glyphs.keys.reject {|g| g.width == default_width}.map! do |glyph|
|
252
|
+
[(@subsetter ? @subsetter.subset_glyph_id(glyph.id) : glyph.id), glyph.width]
|
253
|
+
end.sort!
|
254
|
+
@dict[:DescendantFonts].first.set_widths(widths, default_width: default_width)
|
268
255
|
end
|
269
256
|
|
270
257
|
# Creates the /ToUnicode CMap and updates the font dictionary so that text extraction works
|
271
258
|
# correctly.
|
272
259
|
def create_to_unicode_cmap
|
273
260
|
stream = HexaPDF::StreamData.new do
|
274
|
-
mapping = @encoded_glyphs.keys.
|
261
|
+
mapping = @encoded_glyphs.keys.map do |glyph|
|
275
262
|
# Using 0xFFFD as mentioned in Adobe #5411, last line before section 1.5
|
276
|
-
[
|
277
|
-
|
263
|
+
[(@subsetter ? @subsetter.subset_glyph_id(glyph.id) : glyph.id),
|
264
|
+
@cmap.gid_to_code(glyph.id) || 0xFFFD]
|
265
|
+
end.sort_by(&:first)
|
278
266
|
HexaPDF::Font::CMap.create_to_unicode_cmap(mapping)
|
279
267
|
end
|
280
268
|
stream_obj = @document.add({}, stream: stream)
|
data/lib/hexapdf/font_loader.rb
CHANGED
@@ -68,7 +68,7 @@ module HexaPDF
|
|
68
68
|
#
|
69
69
|
# decode_utf8(str)::
|
70
70
|
# This method needs to convert the given string into an array of glyph objects. The glyph
|
71
|
-
# objects themselves
|
71
|
+
# objects themselves have to respond to \#width which should return their horizontal width.
|
72
72
|
#
|
73
73
|
# encode(glyph)::
|
74
74
|
# This method takes a single glyph object, that needs to be compatible with the font wrapper,
|
data/lib/hexapdf/importer.rb
CHANGED
@@ -116,7 +116,7 @@ module HexaPDF
|
|
116
116
|
@mapper[object.data] = nil
|
117
117
|
else
|
118
118
|
obj = @mapper[object.data] = object.dup
|
119
|
-
obj.document = @destination
|
119
|
+
obj.document = @destination.__getobj__
|
120
120
|
obj.instance_variable_set(:@data, obj.data.dup)
|
121
121
|
obj.data.oid = 0
|
122
122
|
obj.data.gen = 0
|
data/lib/hexapdf/serializer.rb
CHANGED
@@ -231,10 +231,12 @@ module HexaPDF
|
|
231
231
|
def serialize_string(obj)
|
232
232
|
if @encrypter && @object.kind_of?(HexaPDF::Object) && @object.indirect?
|
233
233
|
obj = encrypter.encrypt_string(obj, @object)
|
234
|
-
elsif obj.encoding != Encoding::BINARY && obj =~ /[^ -~\t\r\n]/
|
235
|
-
obj = "\xFE\xFF".b << obj.encode(Encoding::UTF_16BE).force_encoding(Encoding::BINARY)
|
236
234
|
elsif obj.encoding != Encoding::BINARY
|
237
|
-
obj = obj
|
235
|
+
obj = if obj =~ /[^ -~\t\r\n]/
|
236
|
+
"\xFE\xFF".b << obj.encode(Encoding::UTF_16BE).force_encoding(Encoding::BINARY)
|
237
|
+
else
|
238
|
+
obj.b
|
239
|
+
end
|
238
240
|
end
|
239
241
|
"(" << obj.gsub(/[\(\)\\\r]/n) {|m| STRING_ESCAPE_MAP[m]} << ")".freeze
|
240
242
|
end
|
data/lib/hexapdf/type.rb
CHANGED
@@ -61,6 +61,8 @@ module HexaPDF
|
|
61
61
|
autoload(:FontSimple, 'hexapdf/type/font_simple')
|
62
62
|
autoload(:FontType1, 'hexapdf/type/font_type1')
|
63
63
|
autoload(:FontTrueType, 'hexapdf/type/font_true_type')
|
64
|
+
autoload(:FontType0, 'hexapdf/type/font_type0')
|
65
|
+
autoload(:CIDFont, 'hexapdf/type/cid_font')
|
64
66
|
|
65
67
|
end
|
66
68
|
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
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-2017 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
|
+
|
34
|
+
require 'hexapdf/type/font'
|
35
|
+
|
36
|
+
module HexaPDF
|
37
|
+
module Type
|
38
|
+
|
39
|
+
# Represents a generic CIDFont which can only be used as a descendant font of a composite PDF
|
40
|
+
# font.
|
41
|
+
#
|
42
|
+
# See: PDF1.7 s9.7.4
|
43
|
+
class CIDFont < Font
|
44
|
+
|
45
|
+
DEFAULT_WIDTH = 1000 # :nodoc:
|
46
|
+
|
47
|
+
define_field :CIDSystemInfo, type: [Hash, Dictionary], required: true
|
48
|
+
define_field :FontDescriptor, type: :FontDescriptor, indirect: true, required: true
|
49
|
+
define_field :DW, type: Integer, default: DEFAULT_WIDTH
|
50
|
+
define_field :W, type: Array
|
51
|
+
define_field :DW2, type: Array, default: [880, -1100]
|
52
|
+
define_field :W2, type: Array
|
53
|
+
|
54
|
+
|
55
|
+
# Returns the unscaled width of the given CID in glyph units, or 0 if the width for the CID is
|
56
|
+
# missing.
|
57
|
+
#
|
58
|
+
# Note that in contrast to other fonts, the argument must *not* be a code point but a CID!
|
59
|
+
def width(cid)
|
60
|
+
widths[cid] || value[:DW] || DEFAULT_WIDTH
|
61
|
+
end
|
62
|
+
|
63
|
+
# Sets the /W and /DW keys using the given array of [CID, width] pairs and an optional default
|
64
|
+
# width.
|
65
|
+
#
|
66
|
+
# See: PDF1.7 s9.7.4.3
|
67
|
+
def set_widths(widths, default_width: DEFAULT_WIDTH)
|
68
|
+
if widths.empty?
|
69
|
+
(default_width == DEFAULT_WIDTH ? delete(:DW) : self[:DW] = default_width)
|
70
|
+
delete(:W)
|
71
|
+
else
|
72
|
+
self[:DW] = default_width.to_i unless default_width == DEFAULT_WIDTH
|
73
|
+
self[:W] = w = []
|
74
|
+
last_cid = -10
|
75
|
+
cur_widths = nil
|
76
|
+
widths.each do |cid, width|
|
77
|
+
if last_cid + 1 != cid
|
78
|
+
cur_widths = []
|
79
|
+
w << cid << cur_widths
|
80
|
+
end
|
81
|
+
cur_widths << width.to_i
|
82
|
+
last_cid = cid
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# Returns a hash mapping CIDs to their respective width.
|
90
|
+
#
|
91
|
+
# Note that the hash is cached internally when accessed the first time.
|
92
|
+
#
|
93
|
+
# See: PDF1.7 s9.7.4.3
|
94
|
+
def widths
|
95
|
+
document.cache(@data, :widths) do
|
96
|
+
result = {}
|
97
|
+
index = 0
|
98
|
+
array = self[:W] || []
|
99
|
+
|
100
|
+
while index < array.size
|
101
|
+
entry = array[index]
|
102
|
+
value = array[index + 1]
|
103
|
+
if value.kind_of?(Array)
|
104
|
+
value.each_with_index {|width, i| result[entry + i] = width}
|
105
|
+
index += 2
|
106
|
+
else
|
107
|
+
width = array[index + 2]
|
108
|
+
entry.upto(value) {|cid| result[cid] = width}
|
109
|
+
index += 3
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
result
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|