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
data/lib/hexapdf/type/font.rb
CHANGED
@@ -51,28 +51,48 @@ module HexaPDF
|
|
51
51
|
true
|
52
52
|
end
|
53
53
|
|
54
|
-
# Returns the UTF-8 string for the given character code, or
|
55
|
-
# found.
|
54
|
+
# Returns the UTF-8 string for the given character code, or calls the configuration option
|
55
|
+
# 'font.on_missing_unicode_mapping' if no mapping was found.
|
56
56
|
def to_utf8(code)
|
57
|
-
|
58
|
-
|
57
|
+
to_unicode_cmap && to_unicode_cmap.to_unicode(code) || missing_unicode_mapping(code)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the bounding box of the font or +nil+ if it is not found.
|
61
|
+
def bounding_box
|
62
|
+
if key?(:FontDescriptor) && self[:FontDescriptor].key?(:FontBBox)
|
63
|
+
self[:FontDescriptor][:FontBBox].value
|
59
64
|
else
|
60
|
-
|
65
|
+
nil
|
61
66
|
end
|
62
67
|
end
|
63
68
|
|
69
|
+
# Returns +true+ if the font is embedded.
|
70
|
+
def embedded?
|
71
|
+
dict = self[:FontDescriptor]
|
72
|
+
dict && (dict[:FontFile] || dict[:FontFile2] || dict[:FontFile3])
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns the embeeded font file object or +nil+ if the font is not embedded.
|
76
|
+
def font_file
|
77
|
+
embedded?
|
78
|
+
end
|
79
|
+
|
64
80
|
private
|
65
81
|
|
66
82
|
# Parses and caches the ToUnicode CMap.
|
67
83
|
def to_unicode_cmap
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
84
|
+
document.cache(@data, :to_unicode_cmap) do
|
85
|
+
if key?(:ToUnicode)
|
86
|
+
HexaPDF::Font::CMap.parse(self[:ToUnicode].stream)
|
87
|
+
else
|
88
|
+
nil
|
89
|
+
end
|
74
90
|
end
|
75
|
-
|
91
|
+
end
|
92
|
+
|
93
|
+
# Calls the configured proc for handling missing unicode mappings.
|
94
|
+
def missing_unicode_mapping(code)
|
95
|
+
@document.config['font.on_missing_unicode_mapping'].call(code, self)
|
76
96
|
end
|
77
97
|
|
78
98
|
end
|
@@ -54,31 +54,30 @@ module HexaPDF
|
|
54
54
|
#
|
55
55
|
# Note that the encoding is cached internally when accessed the first time.
|
56
56
|
def encoding
|
57
|
-
@encoding
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
encoding = HexaPDF::Font::Encoding.for_name(:StandardEncoding)
|
72
|
-
end
|
57
|
+
document.cache(@data, :encoding) do
|
58
|
+
case (val = self[:Encoding])
|
59
|
+
when Symbol
|
60
|
+
encoding = HexaPDF::Font::Encoding.for_name(val)
|
61
|
+
encoding = encoding_from_font if encoding.nil?
|
62
|
+
encoding
|
63
|
+
when HexaPDF::Dictionary, Hash
|
64
|
+
encoding = val[:BaseEncoding]
|
65
|
+
encoding = HexaPDF::Font::Encoding.for_name(encoding) if encoding
|
66
|
+
unless encoding
|
67
|
+
if embedded? || symbolic?
|
68
|
+
encoding = encoding_from_font
|
69
|
+
else
|
70
|
+
encoding = HexaPDF::Font::Encoding.for_name(:StandardEncoding)
|
73
71
|
end
|
74
|
-
encoding = difference_encoding(encoding, val[:Differences]) if val.key?(:Differences)
|
75
|
-
encoding
|
76
|
-
when nil
|
77
|
-
encoding_from_font
|
78
|
-
else
|
79
|
-
raise HexaPDF::Error, "Unknown value for font's encoding: #{self[:Encoding]}"
|
80
72
|
end
|
73
|
+
encoding = difference_encoding(encoding, val[:Differences]) if val.key?(:Differences)
|
74
|
+
encoding
|
75
|
+
when nil
|
76
|
+
encoding_from_font
|
77
|
+
else
|
78
|
+
raise HexaPDF::Error, "Unknown value for font's encoding: #{self[:Encoding]}"
|
81
79
|
end
|
80
|
+
end
|
82
81
|
end
|
83
82
|
|
84
83
|
# Decodes the given string into an array of character codes.
|
@@ -86,12 +85,11 @@ module HexaPDF
|
|
86
85
|
string.bytes
|
87
86
|
end
|
88
87
|
|
89
|
-
# Returns the UTF-8 string for the given character code, or
|
90
|
-
# found.
|
88
|
+
# Returns the UTF-8 string for the given character code, or calls the configuration option
|
89
|
+
# 'font.on_missing_unicode_mapping' if no mapping was found.
|
91
90
|
def to_utf8(code)
|
92
|
-
|
93
|
-
|
94
|
-
str
|
91
|
+
(to_unicode_cmap && to_unicode_cmap.to_unicode(code)) ||
|
92
|
+
encoding.unicode(code) || missing_unicode_mapping(code)
|
95
93
|
end
|
96
94
|
|
97
95
|
# Returns the unscaled width of the given code point in glyph units, or 0 if the width for
|
@@ -110,32 +108,26 @@ module HexaPDF
|
|
110
108
|
end
|
111
109
|
end
|
112
110
|
|
113
|
-
# Returns the bounding box of the font or +nil+ if it is not found.
|
114
|
-
def bounding_box
|
115
|
-
if key?(:FontDescriptor) && self[:FontDescriptor].key?(:FontBBox)
|
116
|
-
self[:FontDescriptor][:FontBBox].value
|
117
|
-
else
|
118
|
-
nil
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
111
|
# Returns the writing mode which is always :horizontal for simple fonts like Type1.
|
123
112
|
def writing_mode
|
124
113
|
:horizontal
|
125
114
|
end
|
126
115
|
|
127
|
-
# Returns +true+ if the font is embedded.
|
128
|
-
def embedded?
|
129
|
-
dict = self[:FontDescriptor]
|
130
|
-
dict && (dict[:FontFile] || dict[:FontFile2] || dict[:FontFile3])
|
131
|
-
end
|
132
|
-
|
133
116
|
# Returns +true+ if the font is a symbolic font, +false+ if it is not, and +nil+ if it is
|
134
117
|
# not known.
|
135
118
|
def symbolic?
|
136
119
|
self[:FontDescriptor] && self[:FontDescriptor].flagged?(:symbolic) || nil
|
137
120
|
end
|
138
121
|
|
122
|
+
# Returns whether word spacing is applicable when using this font.
|
123
|
+
#
|
124
|
+
# Always returns +true+ for simple fonts.
|
125
|
+
#
|
126
|
+
# See: PDF1.7 s9.3.3
|
127
|
+
def word_spacing_applicable?
|
128
|
+
true
|
129
|
+
end
|
130
|
+
|
139
131
|
private
|
140
132
|
|
141
133
|
# Tries to read the encoding from the embedded font.
|
@@ -0,0 +1,148 @@
|
|
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
|
+
require 'hexapdf/stream'
|
36
|
+
require 'hexapdf/font/cmap'
|
37
|
+
|
38
|
+
module HexaPDF
|
39
|
+
module Type
|
40
|
+
|
41
|
+
# Represents a composite PDF font.
|
42
|
+
#
|
43
|
+
# Composites fonts wrap a descendant CIDFont and use CIDs to identify glyphs. A CID can be
|
44
|
+
# encoded in one or more bytes and an associated CMap specifies how this encoding is done.
|
45
|
+
# Composite fonts also allow for vertical writing mode and support TrueType as well as OpenType
|
46
|
+
# fonts.
|
47
|
+
#
|
48
|
+
# See: PDF1.7 s9.7
|
49
|
+
class FontType0 < Font
|
50
|
+
|
51
|
+
define_field :Subtype, type: Symbol, required: true, default: :Type0
|
52
|
+
define_field :Encoding, type: [Symbol, Stream], required: true
|
53
|
+
define_field :DescendantFonts, type: Array, required: true
|
54
|
+
|
55
|
+
# Returns the CID font of this type 0 font.
|
56
|
+
def descendant_font
|
57
|
+
document.cache(@data, :descendant_font) { document.deref(self[:DescendantFonts][0]) }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the writing mode which is either :horizontal or :vertical.
|
61
|
+
def writing_mode
|
62
|
+
cmap.wmode == 0 ? :horizontal : :vertical
|
63
|
+
end
|
64
|
+
|
65
|
+
# Decodes the given string into an array of CIDs.
|
66
|
+
def decode(string)
|
67
|
+
cmap.read_codes(string)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns the UTF-8 string for the given code, or calls the configuration option
|
71
|
+
# 'font.on_missing_unicode_mapping' if no mapping was found.
|
72
|
+
def to_utf8(code)
|
73
|
+
(to_unicode_cmap && to_unicode_cmap.to_unicode(code)) ||
|
74
|
+
(ucs2_cmap && ucs2_cmap.to_unicode(code)) || missing_unicode_mapping(code)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns the unscaled width of the given CID in glyph units, or 0 if the width for the code
|
78
|
+
# point is missing.
|
79
|
+
def width(code)
|
80
|
+
descendant_font.width(cmap.to_cid(code))
|
81
|
+
end
|
82
|
+
|
83
|
+
# Returns the bounding box of the font or +nil+ if it is not found.
|
84
|
+
def bounding_box
|
85
|
+
descendant_font.bounding_box
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns +true+ if the font is embedded.
|
89
|
+
def embedded?
|
90
|
+
descendant_font.embedded?
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns the embeeded font file object or +nil+ if the font is not embedded.
|
94
|
+
def font_file
|
95
|
+
descendant_font.font_file
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns whether word spacing is applicable when using this font.
|
99
|
+
#
|
100
|
+
# Note that the return value is cached when accessed the first time.
|
101
|
+
#
|
102
|
+
# See: PDF1.7 s9.3.3
|
103
|
+
def word_spacing_applicable?
|
104
|
+
@word_spacing_applicable ||= ((cmap.read_codes("\x20".freeze) && true) rescue false)
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
# Returns the CMap used for decoding strings for this font.
|
110
|
+
#
|
111
|
+
# Note that the CMap is cached internally when accessed the first time.
|
112
|
+
def cmap
|
113
|
+
document.cache(@data, :cmap) do
|
114
|
+
val = self[:Encoding]
|
115
|
+
if val.kind_of?(Symbol)
|
116
|
+
HexaPDF::Font::CMap.for_name(val.to_s)
|
117
|
+
elsif val.kind_of?(HexaPDF::Stream)
|
118
|
+
HexaPDF::Font::CMap.parse(val.stream)
|
119
|
+
else
|
120
|
+
raise HexaPDF::Error, "Unknown value for font's encoding: #{self[:Encoding]}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns the UCS-2 CMap used for extracting text when no ToUnicode CMap is available, or
|
126
|
+
# +nil+ if the UCS-2 CMap could not be determined.
|
127
|
+
#
|
128
|
+
# Note that the CMap is cached internally when accessed the first time.
|
129
|
+
#
|
130
|
+
# See: PDF1.7 s9.10.2
|
131
|
+
def ucs2_cmap
|
132
|
+
document.cache(@data, :ucs2_cmap) do
|
133
|
+
encoding = self[:Encoding]
|
134
|
+
system_info = descendant_font[:CIDSystemInfo]
|
135
|
+
registry = system_info[:Registry]
|
136
|
+
ordering = system_info[:Ordering]
|
137
|
+
if (encoding.kind_of?(Symbol) && HexaPDF::Font::CMap.predefined?(encoding.to_s) &&
|
138
|
+
encoding != :"Identity-H" && encoding != :"Identity-V") ||
|
139
|
+
(registry == "Adobe" && ['GB1', 'CNS1', 'Japan1', 'Korea1'].include?(ordering))
|
140
|
+
HexaPDF::Font::CMap.for_name("#{registry}-#{ordering}-UCS2")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
data/lib/hexapdf/type/form.rb
CHANGED
@@ -105,15 +105,15 @@ module HexaPDF
|
|
105
105
|
#
|
106
106
|
# *Note* that a canvas can only be retrieved for initially empty form XObjects!
|
107
107
|
def canvas
|
108
|
-
|
108
|
+
document.cache(@data, :canvas) do
|
109
109
|
unless stream.empty?
|
110
110
|
raise HexaPDF::Error, "Cannot create a canvas for a form XObjects with contents"
|
111
111
|
end
|
112
|
-
|
113
|
-
self.stream =
|
112
|
+
canvas = Content::Canvas.new(self)
|
113
|
+
self.stream = canvas.stream_data
|
114
114
|
set_filter(:FlateDecode)
|
115
|
+
canvas
|
115
116
|
end
|
116
|
-
@canvas
|
117
117
|
end
|
118
118
|
|
119
119
|
end
|
data/lib/hexapdf/type/page.rb
CHANGED
@@ -135,7 +135,7 @@ module HexaPDF
|
|
135
135
|
define_field :TemplateInstantiated, type: Symbol, version: '1.5'
|
136
136
|
define_field :PresSteps, type: Dictionary, version: '1.5'
|
137
137
|
define_field :UserUnit, type: Numeric, version: '1.6'
|
138
|
-
define_field :VP, type:
|
138
|
+
define_field :VP, type: Array, version: '1.6'
|
139
139
|
|
140
140
|
# Returns +true+ since page objects must always be indirect.
|
141
141
|
def must_be_indirect?
|
@@ -234,7 +234,8 @@ module HexaPDF
|
|
234
234
|
end
|
235
235
|
end
|
236
236
|
|
237
|
-
# Returns the resource dictionary which is automatically created if it
|
237
|
+
# Returns the possibly inherited resource dictionary which is automatically created if it
|
238
|
+
# doesn't exist.
|
238
239
|
def resources
|
239
240
|
self[:Resources] ||= document.wrap({}, type: :XXResources)
|
240
241
|
end
|
@@ -277,8 +278,8 @@ module HexaPDF
|
|
277
278
|
unless [:page, :overlay, :underlay].include?(type)
|
278
279
|
raise ArgumentError, "Invalid value for 'type', expected: :page, :underlay or :overlay"
|
279
280
|
end
|
280
|
-
|
281
|
-
return @
|
281
|
+
cache_key = "#{type}_canvas".intern
|
282
|
+
return document.cache(@data, cache_key) if document.cached?(@data, cache_key)
|
282
283
|
|
283
284
|
if type == :page && key?(:Contents)
|
284
285
|
raise HexaPDF::Error, "Cannot get the canvas for a page with contents"
|
@@ -286,18 +287,18 @@ module HexaPDF
|
|
286
287
|
|
287
288
|
contents = self[:Contents]
|
288
289
|
if contents.nil?
|
289
|
-
@
|
290
|
+
page_canvas = document.cache(@data, :page_canvas, Content::Canvas.new(self))
|
290
291
|
self[:Contents] = document.add({Filter: :FlateDecode},
|
291
|
-
stream:
|
292
|
+
stream: page_canvas.stream_data)
|
292
293
|
end
|
293
294
|
|
294
295
|
if type == :overlay || type == :underlay
|
295
|
-
@
|
296
|
-
@
|
296
|
+
underlay_canvas = document.cache(@data, :underlay_canvas, Content::Canvas.new(self))
|
297
|
+
overlay_canvas = document.cache(@data, :overlay_canvas, Content::Canvas.new(self))
|
297
298
|
|
298
299
|
stream = HexaPDF::StreamData.new do
|
299
300
|
Fiber.yield(" q ")
|
300
|
-
fiber =
|
301
|
+
fiber = underlay_canvas.stream_data.fiber
|
301
302
|
while fiber.alive? && (data = fiber.resume)
|
302
303
|
Fiber.yield(data)
|
303
304
|
end
|
@@ -307,7 +308,7 @@ module HexaPDF
|
|
307
308
|
|
308
309
|
stream = HexaPDF::StreamData.new do
|
309
310
|
Fiber.yield(" Q ")
|
310
|
-
fiber =
|
311
|
+
fiber = overlay_canvas.stream_data.fiber
|
311
312
|
while fiber.alive? && (data = fiber.resume)
|
312
313
|
Fiber.yield(data)
|
313
314
|
end
|
@@ -317,7 +318,7 @@ module HexaPDF
|
|
317
318
|
self[:Contents] = [underlay, *self[:Contents], overlay]
|
318
319
|
end
|
319
320
|
|
320
|
-
@
|
321
|
+
document.cache(@data, cache_key)
|
321
322
|
end
|
322
323
|
|
323
324
|
# Creates a Form XObject from the page's dictionary and contents for the given PDF document.
|
@@ -154,6 +154,20 @@ module HexaPDF
|
|
154
154
|
object_setter(:Font, 'F'.freeze, object)
|
155
155
|
end
|
156
156
|
|
157
|
+
# Returns the property list stored under the given name.
|
158
|
+
#
|
159
|
+
# If the property list is not found, an error is raised.
|
160
|
+
def property_list(name)
|
161
|
+
object_getter(:Properties, name)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Adds the property list to the resources and returns the name under which it is stored.
|
165
|
+
#
|
166
|
+
# If there already exists a name for the given property list, it is just returned.
|
167
|
+
def add_property_list(dict)
|
168
|
+
object_setter(:Properties, 'P'.freeze, dict)
|
169
|
+
end
|
170
|
+
|
157
171
|
private
|
158
172
|
|
159
173
|
# Helper method for returning an entry of a subdictionary.
|
@@ -0,0 +1,77 @@
|
|
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 Utils
|
36
|
+
|
37
|
+
# This module provides some helper functions for graphics.
|
38
|
+
module GraphicsHelpers
|
39
|
+
|
40
|
+
module_function
|
41
|
+
|
42
|
+
# Calculates and returns the requested dimensions for the rectangular object with the given
|
43
|
+
# +width+ and +height+ based on the following: options:
|
44
|
+
#
|
45
|
+
# +rwidth+::
|
46
|
+
# The requested width. If +rheight+ is not specified, it is chosen so that the aspect
|
47
|
+
# ratio is maintained
|
48
|
+
#
|
49
|
+
# +rheight+::
|
50
|
+
# The requested height. If +rwidth+ is not specified, it is chosen so that the aspect
|
51
|
+
# ratio is maintained
|
52
|
+
def calculate_dimensions(width, height, rwidth: nil, rheight: nil)
|
53
|
+
if rwidth && rheight
|
54
|
+
[rwidth, rheight]
|
55
|
+
elsif rwidth
|
56
|
+
[rwidth, height * rwidth / width.to_f]
|
57
|
+
elsif rheight
|
58
|
+
[width * rheight / height.to_f, rheight]
|
59
|
+
else
|
60
|
+
[width, height]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Given two points p0 = (x0, y0) and p1 = (x1, y1), returns the point on the line through
|
65
|
+
# these points that is +distance+ units away from p0.
|
66
|
+
#
|
67
|
+
# v = p1 - p0
|
68
|
+
# result = p0 + distance * v/norm(v)
|
69
|
+
def point_on_line(x0, y0, x1, y1, distance:)
|
70
|
+
norm = Math.sqrt((x1 - x0)**2 + (y1 - y0)**2)
|
71
|
+
[x0 + distance / norm * (x1 - x0), y0 + distance / norm * (y1 - y0)]
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|