prawn 0.1.2 → 0.2.0
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.
- data/README +16 -2
- data/Rakefile +3 -3
- data/data/images/arrow.png +0 -0
- data/data/images/arrow2.png +0 -0
- data/data/images/barcode_issue.png +0 -0
- data/data/images/ruport_type0.png +0 -0
- data/examples/cell.rb +14 -3
- data/examples/chinese_text_wrapping.rb +17 -0
- data/examples/family_based_styling.rb +21 -0
- data/examples/fancy_table.rb +4 -4
- data/examples/flowing_text_with_header_and_footer.rb +72 -0
- data/examples/font_size.rb +2 -2
- data/examples/lazy_bounding_boxes.rb +19 -0
- data/examples/table.rb +13 -11
- data/examples/text_flow.rb +1 -1
- data/lib/prawn.rb +44 -15
- data/lib/prawn/compatibility.rb +20 -7
- data/lib/prawn/document.rb +72 -122
- data/lib/prawn/document/bounding_box.rb +124 -24
- data/lib/prawn/document/internals.rb +107 -0
- data/lib/prawn/document/table.rb +99 -70
- data/lib/prawn/document/text.rb +92 -314
- data/lib/prawn/errors.rb +13 -2
- data/lib/prawn/font.rb +312 -1
- data/lib/prawn/font/cmap.rb +1 -1
- data/lib/prawn/font/metrics.rb +52 -49
- data/lib/prawn/font/wrapping.rb +14 -12
- data/lib/prawn/graphics.rb +23 -74
- data/lib/prawn/graphics/cell.rb +30 -25
- data/lib/prawn/graphics/color.rb +132 -0
- data/lib/prawn/images.rb +37 -16
- data/lib/prawn/images/png.rb +29 -24
- data/lib/prawn/pdf_object.rb +3 -1
- data/spec/bounding_box_spec.rb +12 -3
- data/spec/document_spec.rb +40 -72
- data/spec/font_spec.rb +97 -0
- data/spec/graphics_spec.rb +46 -99
- data/spec/images_spec.rb +4 -21
- data/spec/pdf_object_spec.rb +8 -8
- data/spec/png_spec.rb +47 -12
- data/spec/spec_helper.rb +5 -24
- data/spec/table_spec.rb +53 -59
- data/spec/text_spec.rb +28 -93
- data/vendor/pdf-inspector/README +18 -0
- data/vendor/pdf-inspector/lib/pdf/inspector.rb +25 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +80 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/page.rb +16 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/text.rb +31 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/xobject.rb +19 -0
- metadata +63 -38
- data/examples/on_page_start.rb +0 -17
- data/examples/table_bench.rb +0 -92
- data/spec/box_calculation_spec.rb +0 -17
data/lib/prawn/errors.rb
CHANGED
@@ -23,11 +23,22 @@ module Prawn
|
|
23
23
|
#
|
24
24
|
class UnknownFont < StandardError; end
|
25
25
|
|
26
|
-
# This error is raised when
|
26
|
+
# This error is raised when Prawn is being used on a M17N aware VM,
|
27
27
|
# and the user attempts to add text that isn't compatible with UTF-8
|
28
28
|
# to their document
|
29
29
|
#
|
30
|
-
class IncompatibleStringEncoding < StandardError; end
|
30
|
+
class IncompatibleStringEncoding < StandardError; end
|
31
|
+
|
32
|
+
# This error is raised when Prawn encounters an unknown key in functions
|
33
|
+
# that accept an options hash. This usually means there is a typo in your
|
34
|
+
# code or that the option you are trying to use has a different name than
|
35
|
+
# what you have specified.
|
36
|
+
#
|
37
|
+
class UnknownOption < StandardError; end
|
38
|
+
|
39
|
+
# This error is raised when table data is malformed
|
40
|
+
#
|
41
|
+
class InvalidTableData < StandardError; end
|
31
42
|
|
32
43
|
end
|
33
44
|
end
|
data/lib/prawn/font.rb
CHANGED
@@ -2,4 +2,315 @@
|
|
2
2
|
|
3
3
|
require "prawn/font/wrapping"
|
4
4
|
require "prawn/font/metrics"
|
5
|
-
require "prawn/font/cmap"
|
5
|
+
require "prawn/font/cmap"
|
6
|
+
|
7
|
+
module Prawn
|
8
|
+
|
9
|
+
class Document
|
10
|
+
# Sets the current font.
|
11
|
+
#
|
12
|
+
# The single parameter must be a string. It can be one of the 14 built-in
|
13
|
+
# fonts supported by PDF, or the location of a TTF file. The BUILT_INS
|
14
|
+
# array specifies the valid built in font values.
|
15
|
+
#
|
16
|
+
# pdf.font "Times-Roman"
|
17
|
+
# pdf.font "Chalkboard.ttf"
|
18
|
+
#
|
19
|
+
# If a ttf font is specified, the full file will be embedded in the
|
20
|
+
# rendered PDF. This should be your preferred option in most cases.
|
21
|
+
# It will increase the size of the resulting file, but also make it
|
22
|
+
# more portable.
|
23
|
+
#
|
24
|
+
def font(name=nil, options={})
|
25
|
+
if name
|
26
|
+
if font_families.key?(name)
|
27
|
+
ff = name
|
28
|
+
name = font_families[name][options[:style] || :normal]
|
29
|
+
end
|
30
|
+
Prawn::Font.register(name,:for => self, :family => ff) unless font_registry[name]
|
31
|
+
font_registry[name].add_to_current_page
|
32
|
+
@font_name = name
|
33
|
+
elsif @font_name.nil?
|
34
|
+
Prawn::Font.register("Helvetica", :for => self, :family => "Helvetica")
|
35
|
+
@font_name = "Helvetica"
|
36
|
+
end
|
37
|
+
font_registry[@font_name]
|
38
|
+
end
|
39
|
+
|
40
|
+
# Hash of Font objects keyed by names
|
41
|
+
#
|
42
|
+
def font_registry
|
43
|
+
@font_registry ||= {}
|
44
|
+
end
|
45
|
+
|
46
|
+
# Hash that maps font family names to their styled individual font names
|
47
|
+
#
|
48
|
+
# To add support for another font family, append to this hash, e.g:
|
49
|
+
#
|
50
|
+
# pdf.font_families.update(
|
51
|
+
# "MyTrueTypeFamily" => { :bold => "foo-bold.ttf",
|
52
|
+
# :italic => "foo-italic.ttf",
|
53
|
+
# :bold_italic => "foo-bold-italic.ttf",
|
54
|
+
# :normal => "foo.ttf" })
|
55
|
+
#
|
56
|
+
# This will then allow you to use the fonts like so:
|
57
|
+
#
|
58
|
+
# pdf.font("MyTrueTypeFamily", :style => :bold)
|
59
|
+
# pdf.text "Some bold text"
|
60
|
+
# pdf.font("MyTrueTypeFamily")
|
61
|
+
# pdf.text "Some normal text"
|
62
|
+
#
|
63
|
+
# This assumes that you have appropriate TTF fonts for each style you
|
64
|
+
# wish to support.
|
65
|
+
#
|
66
|
+
def font_families
|
67
|
+
@font_families ||= Hash.new { |h,k| h[k] = {} }.merge!(
|
68
|
+
{ "Courier" => { :bold => "Courier-Bold",
|
69
|
+
:italic => "Courier-Oblique",
|
70
|
+
:bold_italic => "Courier-BoldOblique",
|
71
|
+
:normal => "Courier" },
|
72
|
+
|
73
|
+
"Times-Roman" => { :bold => "Times-Bold",
|
74
|
+
:italic => "Times-Italic",
|
75
|
+
:bold_italic => "Times-BoldItalic",
|
76
|
+
:normal => "Times-Roman" },
|
77
|
+
|
78
|
+
"Helvetica" => { :bold => "Helvetica-Bold",
|
79
|
+
:italic => "Helvetica-Oblique",
|
80
|
+
:bold_italic => "Helvetica-BoldOblique",
|
81
|
+
:normal => "Helvetica" }
|
82
|
+
})
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Provides font information and helper functions.
|
87
|
+
#
|
88
|
+
class Font
|
89
|
+
|
90
|
+
BUILT_INS = %w[ Courier Helvetica Times-Roman Symbol ZapfDingbats
|
91
|
+
Courier-Bold Courier-Oblique Courier-BoldOblique
|
92
|
+
Times-Bold Times-Italic Times-BoldItalic
|
93
|
+
Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique ]
|
94
|
+
|
95
|
+
DEFAULT_SIZE = 12
|
96
|
+
|
97
|
+
def self.register(name,options={})
|
98
|
+
options[:for].font_registry[name] = Font.new(name,options)
|
99
|
+
end
|
100
|
+
|
101
|
+
attr_reader :metrics, :identifier, :reference, :name, :family
|
102
|
+
attr_writer :size
|
103
|
+
|
104
|
+
def initialize(name,options={})
|
105
|
+
@name = name
|
106
|
+
@family = options[:family]
|
107
|
+
|
108
|
+
@metrics = Prawn::Font::Metrics[name]
|
109
|
+
@document = options[:for]
|
110
|
+
|
111
|
+
@document.proc_set :PDF, :Text
|
112
|
+
@size = DEFAULT_SIZE
|
113
|
+
@identifier = :"F#{@document.font_registry.size + 1}"
|
114
|
+
|
115
|
+
case(name)
|
116
|
+
when /\.ttf$/
|
117
|
+
embed_ttf(name)
|
118
|
+
else
|
119
|
+
register_builtin(name)
|
120
|
+
end
|
121
|
+
|
122
|
+
add_to_current_page
|
123
|
+
end
|
124
|
+
|
125
|
+
# Sets the default font size for use within a block. Individual overrides
|
126
|
+
# can be used as desired. The previous font size will be restored after the
|
127
|
+
# block.
|
128
|
+
#
|
129
|
+
# Prawn::Document.generate("font_size.pdf") do
|
130
|
+
# font.size = 16
|
131
|
+
# text "At size 16"
|
132
|
+
#
|
133
|
+
# font.size(10) do
|
134
|
+
# text "At size 10"
|
135
|
+
# text "At size 6", :size => 6
|
136
|
+
# text "At size 10"
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
# text "At size 16"
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# When called without an argument, this method returns the current font
|
143
|
+
# size.
|
144
|
+
#
|
145
|
+
def size(points=nil)
|
146
|
+
return @size unless points
|
147
|
+
size_before_yield = @size
|
148
|
+
@size = points
|
149
|
+
yield
|
150
|
+
@size = size_before_yield
|
151
|
+
end
|
152
|
+
|
153
|
+
# Gets width of string in PDF points at current font size
|
154
|
+
#
|
155
|
+
def width_of(string)
|
156
|
+
@metrics.string_width(string,@size)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Gets height of text in PDF points at current font size.
|
160
|
+
# Text +:line_width+ must be specified in PDF points.
|
161
|
+
#
|
162
|
+
def height_of(text,options={})
|
163
|
+
@metrics.string_height( text, :font_size => @size,
|
164
|
+
:line_width => options[:line_width] )
|
165
|
+
end
|
166
|
+
|
167
|
+
# Gets height of current font in PDF points at current font size
|
168
|
+
#
|
169
|
+
def height
|
170
|
+
@metrics.font_height(@size)
|
171
|
+
end
|
172
|
+
|
173
|
+
def ascender # :nodoc:
|
174
|
+
@metrics.ascender / 1000.0 * @size
|
175
|
+
end
|
176
|
+
|
177
|
+
def descender # :nodoc:
|
178
|
+
@metrics.descender / 1000.0 * @size
|
179
|
+
end
|
180
|
+
|
181
|
+
def normalize_encoding(text) # :nodoc:
|
182
|
+
# check the string is encoded sanely
|
183
|
+
# - UTF-8 for TTF fonts
|
184
|
+
# - ISO-8859-1 for Built-In fonts
|
185
|
+
if @metrics.type0?
|
186
|
+
normalize_ttf_encoding(text)
|
187
|
+
else
|
188
|
+
normalize_builtin_encoding(text)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def add_to_current_page #:nodoc:
|
193
|
+
@document.page_fonts.merge!(@identifier => @reference)
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
# built-in fonts only work with latin encoding, so translate the string
|
199
|
+
def normalize_builtin_encoding(text)
|
200
|
+
if text.respond_to?(:encode!)
|
201
|
+
text.encode!("ISO-8859-1")
|
202
|
+
else
|
203
|
+
require 'iconv'
|
204
|
+
text.replace Iconv.conv('ISO-8859-1//TRANSLIT', 'utf-8', text)
|
205
|
+
end
|
206
|
+
rescue
|
207
|
+
raise Prawn::Errors::IncompatibleStringEncoding, "When using a " +
|
208
|
+
"builtin font, only characters that exist in " +
|
209
|
+
"WinAnsi/ISO-8859-1 are allowed."
|
210
|
+
end
|
211
|
+
|
212
|
+
def normalize_ttf_encoding(text)
|
213
|
+
# TODO: if the current font is a built in one, we can't use the utf-8
|
214
|
+
# string provided by the user. We should convert it to WinAnsi or
|
215
|
+
# MacRoman or some such.
|
216
|
+
if text.respond_to?(:encode!)
|
217
|
+
# if we're running under a M17n aware VM, ensure the string provided is
|
218
|
+
# UTF-8 (by converting it if necessary)
|
219
|
+
begin
|
220
|
+
text.encode!("UTF-8")
|
221
|
+
rescue
|
222
|
+
raise Prawn::Errors::IncompatibleStringEncoding, "Encoding " +
|
223
|
+
"#{text.encoding} can not be transparently converted to UTF-8. " +
|
224
|
+
"Please ensure the encoding of the string you are attempting " +
|
225
|
+
"to use is set correctly"
|
226
|
+
end
|
227
|
+
else
|
228
|
+
# on a non M17N aware VM, use unpack as a hackish way to verify the
|
229
|
+
# string is valid utf-8. I thought it was better than loading iconv
|
230
|
+
# though.
|
231
|
+
begin
|
232
|
+
text.unpack("U*")
|
233
|
+
rescue
|
234
|
+
raise Prawn::Errors::IncompatibleStringEncoding, "The string you " +
|
235
|
+
"are attempting to render is not encoded in valid UTF-8."
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def register_builtin(name)
|
241
|
+
unless BUILT_INS.include?(name)
|
242
|
+
raise Prawn::Errors::UnknownFont, "#{name} is not a known font."
|
243
|
+
end
|
244
|
+
|
245
|
+
@reference = @document.ref( :Type => :Font,
|
246
|
+
:Subtype => :Type1,
|
247
|
+
:BaseFont => name.to_sym,
|
248
|
+
:Encoding => :WinAnsiEncoding)
|
249
|
+
end
|
250
|
+
|
251
|
+
def embed_ttf(file)
|
252
|
+
unless File.file?(file)
|
253
|
+
raise ArgumentError, "file #{file} does not exist"
|
254
|
+
end
|
255
|
+
|
256
|
+
basename = @metrics.basename
|
257
|
+
|
258
|
+
raise "Can't detect a postscript name for #{file}" if basename.nil?
|
259
|
+
|
260
|
+
@encodings = @metrics.enc_table
|
261
|
+
|
262
|
+
if @encodings.nil?
|
263
|
+
raise "#{file} missing the required encoding table"
|
264
|
+
end
|
265
|
+
|
266
|
+
font_content = File.open(file,"rb") { |f| f.read }
|
267
|
+
compressed_font = Zlib::Deflate.deflate(font_content)
|
268
|
+
|
269
|
+
fontfile = @document.ref(:Length => compressed_font.size,
|
270
|
+
:Length1 => font_content.size,
|
271
|
+
:Filter => :FlateDecode )
|
272
|
+
fontfile << compressed_font
|
273
|
+
|
274
|
+
# TODO: Not sure what to do about CapHeight, as ttf2afm doesn't
|
275
|
+
# pick it up. Missing proper StemV and flags
|
276
|
+
#
|
277
|
+
descriptor = @document.ref(:Type => :FontDescriptor,
|
278
|
+
:FontName => basename,
|
279
|
+
:FontFile2 => fontfile,
|
280
|
+
:FontBBox => @metrics.bbox,
|
281
|
+
:Flags => 32, # FIXME: additional flags
|
282
|
+
:StemV => 0,
|
283
|
+
:ItalicAngle => 0,
|
284
|
+
:Ascent => @metrics.ascender,
|
285
|
+
:Descent => @metrics.descender )
|
286
|
+
|
287
|
+
descendant = @document.ref(:Type => :Font,
|
288
|
+
:Subtype => :CIDFontType2, # CID, TTF
|
289
|
+
:BaseFont => basename,
|
290
|
+
:CIDSystemInfo => { :Registry => "Adobe",
|
291
|
+
:Ordering => "Identity",
|
292
|
+
:Supplement => 0 },
|
293
|
+
:FontDescriptor => descriptor,
|
294
|
+
:W => @metrics.glyph_widths,
|
295
|
+
:CIDToGIDMap => :Identity )
|
296
|
+
|
297
|
+
to_unicode_content = @metrics.to_unicode_cmap.to_s
|
298
|
+
compressed_to_unicode = Zlib::Deflate.deflate(to_unicode_content)
|
299
|
+
|
300
|
+
to_unicode = @document.ref(:Length => compressed_to_unicode.size,
|
301
|
+
:Length1 => to_unicode_content.size,
|
302
|
+
:Filter => :FlateDecode )
|
303
|
+
to_unicode << compressed_to_unicode
|
304
|
+
|
305
|
+
@reference = @document.ref(:Type => :Font,
|
306
|
+
:Subtype => :Type0,
|
307
|
+
:BaseFont => basename,
|
308
|
+
:DescendantFonts => [descendant],
|
309
|
+
:Encoding => :"Identity-H",
|
310
|
+
:ToUnicode => to_unicode)
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
end
|
315
|
+
|
316
|
+
end
|
data/lib/prawn/font/cmap.rb
CHANGED
data/lib/prawn/font/metrics.rb
CHANGED
@@ -10,27 +10,26 @@
|
|
10
10
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
11
11
|
|
12
12
|
module Prawn
|
13
|
-
|
13
|
+
class Font #:nodoc:
|
14
14
|
class Metrics #:nodoc:
|
15
15
|
|
16
16
|
include Prawn::Font::Wrapping
|
17
17
|
|
18
18
|
def self.[](font)
|
19
|
-
data[font] ||=
|
20
|
-
when /\.ttf$/
|
21
|
-
TTF.new(font)
|
22
|
-
else
|
23
|
-
Adobe.new(font)
|
24
|
-
end
|
19
|
+
data[font] ||= (font.match(/\.ttf$/) ? TTF : Adobe).new(font)
|
25
20
|
end
|
26
21
|
|
27
22
|
def self.data
|
28
23
|
@data ||= {}
|
29
24
|
end
|
30
25
|
|
31
|
-
def string_height(string,options={})
|
26
|
+
def string_height(string,options={})
|
32
27
|
string = naive_wrap(string, options[:line_width], options[:font_size])
|
33
28
|
string.lines.to_a.length * font_height(options[:font_size])
|
29
|
+
end
|
30
|
+
|
31
|
+
def font_height(size)
|
32
|
+
(ascender - descender + line_gap) * size / 1000.0
|
34
33
|
end
|
35
34
|
|
36
35
|
class Adobe < Metrics #:nodoc:
|
@@ -85,13 +84,9 @@ module Prawn
|
|
85
84
|
fontbbox.split(/\s+/).map { |e| Integer(e) }
|
86
85
|
end
|
87
86
|
|
88
|
-
def font_height(font_size)
|
89
|
-
Float(bbox[3] - bbox[1]) * font_size / 1000.0
|
90
|
-
end
|
91
|
-
|
92
87
|
# calculates the width of the supplied string.
|
93
88
|
# String *must* be encoded as iso-8859-1
|
94
|
-
def string_width(string, font_size, options = {})
|
89
|
+
def string_width(string, font_size, options = {})
|
95
90
|
scale = font_size / 1000.0
|
96
91
|
|
97
92
|
if options[:kerning]
|
@@ -116,8 +111,8 @@ module Prawn
|
|
116
111
|
def kern(string)
|
117
112
|
kerned = string.unpack("C*").inject([]) do |a,r|
|
118
113
|
if a.last.is_a? Array
|
119
|
-
if
|
120
|
-
a <<
|
114
|
+
if k = latin_kern_pairs_table[[a.last.last, r]]
|
115
|
+
a << k << [r]
|
121
116
|
else
|
122
117
|
a.last << r
|
123
118
|
end
|
@@ -134,7 +129,7 @@ module Prawn
|
|
134
129
|
}
|
135
130
|
end
|
136
131
|
|
137
|
-
def latin_kern_pairs_table
|
132
|
+
def latin_kern_pairs_table
|
138
133
|
@kern_pairs_table ||= @kern_pairs.inject({}) do |h,p|
|
139
134
|
h[p[0].map { |n| ISOLatin1Encoding.index(n) }] = p[1]
|
140
135
|
h
|
@@ -153,16 +148,16 @@ module Prawn
|
|
153
148
|
|
154
149
|
def descender
|
155
150
|
@attributes["descender"].to_i
|
151
|
+
end
|
152
|
+
|
153
|
+
def line_gap
|
154
|
+
Float(bbox[3] - bbox[1]) - (ascender - descender)
|
156
155
|
end
|
157
156
|
|
158
157
|
# Hackish, but does the trick for now.
|
159
158
|
def method_missing(method, *args, &block)
|
160
159
|
name = method.to_s.delete("_")
|
161
|
-
|
162
|
-
@attributes[name]
|
163
|
-
else
|
164
|
-
super
|
165
|
-
end
|
160
|
+
@attributes.include?(name) ? @attributes[name] : super
|
166
161
|
end
|
167
162
|
|
168
163
|
def metrics_path
|
@@ -170,10 +165,10 @@ module Prawn
|
|
170
165
|
@metrics_path ||= m.split(':')
|
171
166
|
else
|
172
167
|
@metrics_path ||= [
|
173
|
-
"/usr/lib/afm",
|
168
|
+
".", "/usr/lib/afm",
|
174
169
|
"/usr/local/lib/afm",
|
175
170
|
"/usr/openwin/lib/fonts/afm/",
|
176
|
-
Prawn::BASEDIR+'/data/fonts/'
|
171
|
+
Prawn::BASEDIR+'/data/fonts/']
|
177
172
|
end
|
178
173
|
end
|
179
174
|
|
@@ -188,7 +183,8 @@ module Prawn
|
|
188
183
|
# perform any changes to the string that need to happen
|
189
184
|
# before it is rendered to the canvas
|
190
185
|
#
|
191
|
-
# String *must* be encoded as iso-8859-1
|
186
|
+
# String *must* be encoded as iso-8859-1
|
187
|
+
#
|
192
188
|
def convert_text(text, options={})
|
193
189
|
options[:kerning] ? kern(text) : text
|
194
190
|
end
|
@@ -243,13 +239,17 @@ module Prawn
|
|
243
239
|
end
|
244
240
|
end
|
245
241
|
|
246
|
-
class TTF < Metrics #:nodoc:
|
242
|
+
class TTF < Metrics #:nodoc:
|
243
|
+
|
244
|
+
attr_accessor :ttf
|
247
245
|
|
248
246
|
def initialize(font)
|
249
247
|
@ttf = ::Font::TTF::File.open(font,"rb")
|
250
|
-
@attributes
|
251
|
-
@glyph_widths
|
252
|
-
@bounding_boxes
|
248
|
+
@attributes = {}
|
249
|
+
@glyph_widths = {}
|
250
|
+
@bounding_boxes = {}
|
251
|
+
@char_widths = {}
|
252
|
+
@has_kerning_data = !kern_pairs_table.empty?
|
253
253
|
end
|
254
254
|
|
255
255
|
def cmap
|
@@ -275,7 +275,9 @@ module Prawn
|
|
275
275
|
|
276
276
|
# TODO: NASTY.
|
277
277
|
def kern(string,options={})
|
278
|
-
|
278
|
+
a = []
|
279
|
+
|
280
|
+
string.unpack("U*").each do |r|
|
279
281
|
if a.last.is_a? Array
|
280
282
|
if kern = kern_pairs_table[[cmap[a.last.last], cmap[r]]]
|
281
283
|
kern *= scale_factor
|
@@ -287,7 +289,9 @@ module Prawn
|
|
287
289
|
a << [r]
|
288
290
|
end
|
289
291
|
a
|
290
|
-
end
|
292
|
+
end
|
293
|
+
|
294
|
+
a.map { |r|
|
291
295
|
if options[:skip_conversion]
|
292
296
|
r.is_a?(Array) ? r.pack("U*") : r
|
293
297
|
else
|
@@ -335,10 +339,10 @@ module Prawn
|
|
335
339
|
|
336
340
|
def descender
|
337
341
|
Integer(@ttf.get_table(:hhea).descender * scale_factor)
|
338
|
-
end
|
339
|
-
|
340
|
-
def
|
341
|
-
(
|
342
|
+
end
|
343
|
+
|
344
|
+
def line_gap
|
345
|
+
Integer(@ttf.get_table(:hhea).line_gap * scale_factor)
|
342
346
|
end
|
343
347
|
|
344
348
|
def basename
|
@@ -377,19 +381,18 @@ module Prawn
|
|
377
381
|
s.is_a? ::Font::TTF::Table::Kern::KerningSubtable0 }
|
378
382
|
|
379
383
|
if table
|
380
|
-
@kern_pairs_table
|
381
|
-
h[[p.left, p.right]] = p.value
|
382
|
-
h
|
384
|
+
@kern_pairs_table = table.kerning_pairs.inject({}) do |h,p|
|
385
|
+
h[[p.left, p.right]] = p.value; h
|
383
386
|
end
|
384
387
|
else
|
385
388
|
@kern_pairs_table = {}
|
386
|
-
end
|
389
|
+
end
|
390
|
+
rescue ::Font::TTF::TableMissing
|
391
|
+
@kern_pairs_table = {}
|
387
392
|
end
|
388
393
|
|
389
394
|
def has_kerning_data?
|
390
|
-
|
391
|
-
rescue ::Font::TTF::TableMissing
|
392
|
-
false
|
395
|
+
@has_kerning_data
|
393
396
|
end
|
394
397
|
|
395
398
|
def type0?
|
@@ -398,9 +401,9 @@ module Prawn
|
|
398
401
|
|
399
402
|
def convert_text(text,options)
|
400
403
|
text = text.chomp
|
401
|
-
if options[:kerning]
|
402
|
-
kern(text)
|
403
|
-
else
|
404
|
+
if options[:kerning]
|
405
|
+
kern(text)
|
406
|
+
else
|
404
407
|
unicode_codepoints = text.unpack("U*")
|
405
408
|
glyph_codes = unicode_codepoints.map { |u|
|
406
409
|
enc_table.get_glyph_id_for_unicode(u)
|
@@ -413,15 +416,15 @@ module Prawn
|
|
413
416
|
|
414
417
|
def hmtx
|
415
418
|
@hmtx ||= @ttf.get_table(:hmtx).metrics
|
416
|
-
end
|
417
|
-
|
418
|
-
def character_width_by_code(code)
|
419
|
+
end
|
420
|
+
|
421
|
+
def character_width_by_code(code)
|
419
422
|
return 0 unless cmap[code]
|
420
|
-
Integer(hmtx[cmap[code]][0] * scale_factor)
|
423
|
+
@char_widths[code] ||= Integer(hmtx[cmap[code]][0] * scale_factor)
|
421
424
|
end
|
422
425
|
|
423
426
|
def scale_factor
|
424
|
-
@scale ||=
|
427
|
+
@scale ||= 1000 * Float(@ttf.get_table(:head).units_per_em)**-1
|
425
428
|
end
|
426
429
|
|
427
430
|
end
|