prawn 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|