prawn 0.2.3 → 0.3.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 +6 -10
- data/Rakefile +4 -13
- data/data/encodings/win_ansi.txt +29 -0
- data/data/images/fractal.jpg +0 -0
- data/data/images/letterhead.jpg +0 -0
- data/examples/bounding_box/bounding_boxes.rb +44 -0
- data/examples/bounding_box/lazy_bounding_boxes.rb +28 -0
- data/examples/bounding_box/padded_box.rb +24 -0
- data/examples/{russian_boxes.rb → bounding_box/russian_boxes.rb} +9 -6
- data/examples/general/background.rb +20 -0
- data/examples/{canvas.rb → general/canvas.rb} +6 -2
- data/examples/general/measurement_units.rb +52 -0
- data/examples/{multi_page_layout.rb → general/multi_page_layout.rb} +6 -3
- data/examples/{page_geometry.rb → general/page_geometry.rb} +6 -2
- data/examples/{image.rb → graphics/basic_images.rb} +8 -4
- data/examples/graphics/cmyk.rb +13 -0
- data/examples/graphics/curves.rb +12 -0
- data/examples/{hexagon.rb → graphics/hexagon.rb} +5 -5
- data/examples/graphics/image_fit.rb +16 -0
- data/examples/graphics/image_flow.rb +38 -0
- data/examples/graphics/image_position.rb +18 -0
- data/examples/{line.rb → graphics/line.rb} +4 -2
- data/examples/{png_types.rb → graphics/png_types.rb} +4 -4
- data/examples/{polygons.rb → graphics/polygons.rb} +5 -4
- data/examples/graphics/remote_images.rb +12 -0
- data/examples/{ruport_helpers.rb → graphics/ruport_style_helpers.rb} +8 -5
- data/examples/graphics/stroke_bounds.rb +23 -0
- data/examples/{chinese_text_wrapping.rb → m17n/chinese_text_wrapping.rb} +7 -4
- data/examples/m17n/euro.rb +16 -0
- data/examples/m17n/sjis.rb +29 -0
- data/examples/m17n/utf8.rb +14 -0
- data/examples/m17n/win_ansi_charset.rb +55 -0
- data/examples/{addressbook.csv → table/addressbook.csv} +0 -0
- data/examples/{cell.rb → table/cell.rb} +8 -6
- data/examples/{currency.csv → table/currency.csv} +0 -0
- data/examples/{fancy_table.rb → table/fancy_table.rb} +9 -6
- data/examples/{ruport_formatter.rb → table/ruport_formatter.rb} +6 -3
- data/examples/{table.rb → table/table.rb} +6 -2
- data/examples/table/table_alignment.rb +18 -0
- data/examples/table/table_border_color.rb +17 -0
- data/examples/table/table_colspan.rb +19 -0
- data/examples/table/table_header_color.rb +19 -0
- data/examples/table/table_header_underline.rb +15 -0
- data/examples/{alignment.rb → text/alignment.rb} +5 -2
- data/examples/text/family_based_styling.rb +25 -0
- data/examples/{flowing_text_with_header_and_footer.rb → text/flowing_text_with_header_and_footer.rb} +19 -8
- data/examples/text/font_calculations.rb +91 -0
- data/examples/text/font_size.rb +34 -0
- data/examples/{kerning.rb → text/kerning.rb} +5 -1
- data/examples/text/simple_text.rb +18 -0
- data/examples/text/simple_text_ttf.rb +18 -0
- data/examples/{span.rb → text/span.rb} +5 -2
- data/examples/text/text_box.rb +26 -0
- data/examples/{text_flow.rb → text/text_flow.rb} +5 -2
- data/lib/prawn.rb +26 -20
- data/lib/prawn/compatibility.rb +5 -8
- data/lib/prawn/document.rb +29 -13
- data/lib/prawn/document/annotations.rb +63 -0
- data/lib/prawn/document/bounding_box.rb +18 -3
- data/lib/prawn/document/destinations.rb +81 -0
- data/lib/prawn/document/internals.rb +16 -2
- data/lib/prawn/document/page_geometry.rb +58 -57
- data/lib/prawn/document/span.rb +8 -0
- data/lib/prawn/document/table.rb +81 -31
- data/lib/prawn/document/text.rb +66 -21
- data/lib/prawn/document/text/box.rb +77 -0
- data/lib/prawn/encoding.rb +121 -0
- data/lib/prawn/errors.rb +4 -0
- data/lib/prawn/font.rb +70 -42
- data/lib/prawn/font/metrics.rb +64 -119
- data/lib/prawn/graphics.rb +105 -87
- data/lib/prawn/graphics/cell.rb +55 -28
- data/lib/prawn/graphics/color.rb +8 -0
- data/lib/prawn/images.rb +55 -12
- data/lib/prawn/images/jpg.rb +2 -1
- data/lib/prawn/images/png.rb +2 -1
- data/lib/prawn/literal_string.rb +14 -0
- data/lib/prawn/measurement_extensions.rb +46 -0
- data/lib/prawn/measurements.rb +71 -0
- data/lib/prawn/name_tree.rb +165 -0
- data/lib/prawn/pdf_object.rb +8 -1
- data/spec/annotations_spec.rb +90 -0
- data/spec/destinations_spec.rb +15 -0
- data/spec/document_spec.rb +39 -2
- data/spec/font_spec.rb +22 -0
- data/spec/graphics_spec.rb +99 -87
- data/spec/images_spec.rb +29 -1
- data/spec/measurement_units_spec.rb +23 -0
- data/spec/metrics_spec.rb +3 -2
- data/spec/name_tree_spec.rb +103 -0
- data/spec/pdf_object_spec.rb +15 -5
- data/spec/png_spec.rb +14 -14
- data/spec/spec_helper.rb +8 -6
- data/spec/table_spec.rb +40 -0
- data/spec/text_spec.rb +6 -4
- data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
- data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
- data/vendor/ttfunk/example.rb +5 -0
- data/vendor/ttfunk/lib/ttfunk.rb +48 -0
- data/vendor/ttfunk/lib/ttfunk/table.rb +27 -0
- data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +94 -0
- data/vendor/ttfunk/lib/ttfunk/table/directory.rb +25 -0
- data/vendor/ttfunk/lib/ttfunk/table/head.rb +25 -0
- data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +27 -0
- data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +20 -0
- data/vendor/ttfunk/lib/ttfunk/table/kern.rb +48 -0
- data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +17 -0
- data/vendor/ttfunk/lib/ttfunk/table/name.rb +52 -0
- metadata +93 -62
- data/examples/bounding_boxes.rb +0 -30
- data/examples/curves.rb +0 -10
- data/examples/family_based_styling.rb +0 -21
- data/examples/font_size.rb +0 -19
- data/examples/image2.rb +0 -13
- data/examples/image_flow.rb +0 -29
- data/examples/lazy_bounding_boxes.rb +0 -19
- data/examples/remote_images.rb +0 -7
- data/examples/simple_text.rb +0 -15
- data/examples/simple_text_ttf.rb +0 -16
- data/examples/sjis.rb +0 -21
- data/examples/utf8.rb +0 -12
- data/vendor/font_ttf/ttf.rb +0 -20
- data/vendor/font_ttf/ttf/datatypes.rb +0 -189
- data/vendor/font_ttf/ttf/encodings.rb +0 -140
- data/vendor/font_ttf/ttf/exceptions.rb +0 -28
- data/vendor/font_ttf/ttf/file.rb +0 -290
- data/vendor/font_ttf/ttf/fontchunk.rb +0 -77
- data/vendor/font_ttf/ttf/table/cmap.rb +0 -408
- data/vendor/font_ttf/ttf/table/cvt.rb +0 -49
- data/vendor/font_ttf/ttf/table/fpgm.rb +0 -48
- data/vendor/font_ttf/ttf/table/gasp.rb +0 -88
- data/vendor/font_ttf/ttf/table/glyf.rb +0 -452
- data/vendor/font_ttf/ttf/table/head.rb +0 -86
- data/vendor/font_ttf/ttf/table/hhea.rb +0 -96
- data/vendor/font_ttf/ttf/table/hmtx.rb +0 -98
- data/vendor/font_ttf/ttf/table/kern.rb +0 -186
- data/vendor/font_ttf/ttf/table/loca.rb +0 -75
- data/vendor/font_ttf/ttf/table/maxp.rb +0 -81
- data/vendor/font_ttf/ttf/table/name.rb +0 -222
- data/vendor/font_ttf/ttf/table/os2.rb +0 -172
- data/vendor/font_ttf/ttf/table/post.rb +0 -120
- data/vendor/font_ttf/ttf/table/prep.rb +0 -27
- data/vendor/font_ttf/ttf/table/vhea.rb +0 -45
- data/vendor/font_ttf/ttf/table/vmtx.rb +0 -36
data/lib/prawn/font/metrics.rb
CHANGED
@@ -9,6 +9,8 @@
|
|
9
9
|
#
|
10
10
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
11
11
|
|
12
|
+
require 'prawn/encoding'
|
13
|
+
|
12
14
|
module Prawn
|
13
15
|
class Font
|
14
16
|
class Metrics #:nodoc:
|
@@ -33,37 +35,6 @@ module Prawn
|
|
33
35
|
end
|
34
36
|
|
35
37
|
class Adobe < Metrics #:nodoc:
|
36
|
-
|
37
|
-
ISOLatin1Encoding = %w[
|
38
|
-
.notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef
|
39
|
-
.notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef
|
40
|
-
.notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef
|
41
|
-
.notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef space
|
42
|
-
exclam quotedbl numbersign dollar percent ampersand quoteright
|
43
|
-
parenleft parenright asterisk plus comma minus period slash zero one
|
44
|
-
two three four five six seven eight nine colon semicolon less equal
|
45
|
-
greater question at A B C D E F G H I J K L M N O P Q R S
|
46
|
-
T U V W X Y Z bracketleft backslash bracketright asciicircum
|
47
|
-
underscore quoteleft a b c d e f g h i j k l m n o p q r s
|
48
|
-
t u v w x y z braceleft bar braceright asciitilde .notdef .notdef
|
49
|
-
.notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef
|
50
|
-
.notdef .notdef .notdef .notdef .notdef .notdef .notdef dotlessi grave
|
51
|
-
acute circumflex tilde macron breve dotaccent dieresis .notdef ring
|
52
|
-
cedilla .notdef hungarumlaut ogonek caron space exclamdown cent
|
53
|
-
sterling currency yen brokenbar section dieresis copyright ordfeminine
|
54
|
-
guillemotleft logicalnot hyphen registered macron degree plusminus
|
55
|
-
twosuperior threesuperior acute mu paragraph periodcentered cedilla
|
56
|
-
onesuperior ordmasculine guillemotright onequarter onehalf threequarters
|
57
|
-
questiondown Agrave Aacute Acircumflex Atilde Adieresis Aring AE
|
58
|
-
Ccedilla Egrave Eacute Ecircumflex Edieresis Igrave Iacute Icircumflex
|
59
|
-
Idieresis Eth Ntilde Ograve Oacute Ocircumflex Otilde Odieresis
|
60
|
-
multiply Oslash Ugrave Uacute Ucircumflex Udieresis Yacute Thorn
|
61
|
-
germandbls agrave aacute acircumflex atilde adieresis aring ae
|
62
|
-
ccedilla egrave eacute ecircumflex edieresis igrave iacute icircumflex
|
63
|
-
idieresis eth ntilde ograve oacute ocircumflex otilde odieresis divide
|
64
|
-
oslash ugrave uacute ucircumflex udieresis yacute thorn ydieresis
|
65
|
-
]
|
66
|
-
|
67
38
|
attr_reader :attributes
|
68
39
|
|
69
40
|
def initialize(font_name)
|
@@ -85,7 +56,9 @@ module Prawn
|
|
85
56
|
end
|
86
57
|
|
87
58
|
# calculates the width of the supplied string.
|
88
|
-
#
|
59
|
+
#
|
60
|
+
# String *must* be encoded as WinAnsi
|
61
|
+
#
|
89
62
|
def string_width(string, font_size, options = {})
|
90
63
|
scale = font_size / 1000.0
|
91
64
|
|
@@ -107,7 +80,8 @@ module Prawn
|
|
107
80
|
# converts a string into an array with spacing offsets
|
108
81
|
# bewteen characters that need to be kerned
|
109
82
|
#
|
110
|
-
# String *must* be encoded as
|
83
|
+
# String *must* be encoded as WinAnsi
|
84
|
+
#
|
111
85
|
def kern(string)
|
112
86
|
kerned = string.unpack("C*").inject([]) do |a,r|
|
113
87
|
if a.last.is_a? Array
|
@@ -131,14 +105,14 @@ module Prawn
|
|
131
105
|
|
132
106
|
def latin_kern_pairs_table
|
133
107
|
@kern_pairs_table ||= @kern_pairs.inject({}) do |h,p|
|
134
|
-
h[p[0].map { |n|
|
108
|
+
h[p[0].map { |n| Encoding::WinAnsi::CHARACTERS.index(n) }] = p[1]
|
135
109
|
h
|
136
110
|
end
|
137
111
|
end
|
138
112
|
|
139
113
|
def latin_glyphs_table
|
140
114
|
@glyphs_table ||= (0..255).map do |i|
|
141
|
-
@glyph_widths[
|
115
|
+
@glyph_widths[Encoding::WinAnsi::CHARACTERS[i]].to_i
|
142
116
|
end
|
143
117
|
end
|
144
118
|
|
@@ -183,7 +157,7 @@ module Prawn
|
|
183
157
|
# perform any changes to the string that need to happen
|
184
158
|
# before it is rendered to the canvas
|
185
159
|
#
|
186
|
-
# String *must* be encoded as
|
160
|
+
# String *must* be encoded as WinAnsi
|
187
161
|
#
|
188
162
|
def convert_text(text, options={})
|
189
163
|
options[:kerning] ? kern(text) : text
|
@@ -199,44 +173,45 @@ module Prawn
|
|
199
173
|
@metrics_path.join("\n")
|
200
174
|
end
|
201
175
|
|
202
|
-
def parse_afm(
|
176
|
+
def parse_afm(file_name)
|
203
177
|
section = []
|
204
|
-
|
205
|
-
File.
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
next
|
214
|
-
end
|
215
|
-
|
216
|
-
if section == ["FontMetrics", "CharMetrics"]
|
217
|
-
next unless line =~ /^CH?\s/
|
218
|
-
|
219
|
-
name = line[/\bN\s+(\.?\w+)\s*;/, 1]
|
220
|
-
@glyph_widths[name] = line[/\bWX\s+(\d+)\s*;/, 1].to_i
|
221
|
-
@bounding_boxes[name] = line[/\bB\s+([^;]+);/, 1].to_s.rstrip
|
222
|
-
elsif section == ["FontMetrics", "KernData", "KernPairs"]
|
223
|
-
next unless line =~ /^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/
|
224
|
-
@kern_pairs[[$1, $2]] = $3.to_i
|
225
|
-
elsif section == ["FontMetrics", "KernData", "TrackKern"]
|
226
|
-
next
|
227
|
-
elsif section == ["FontMetrics", "Composites"]
|
228
|
-
next
|
229
|
-
elsif line =~ /(^\w+)\s+(.*)/
|
230
|
-
key, value = $1.to_s.downcase, $2
|
231
|
-
|
232
|
-
@attributes[key] = @attributes[key] ?
|
233
|
-
Array(@attributes[key]) << value : value
|
234
|
-
else
|
235
|
-
warn "Can't parse: #{line}"
|
236
|
-
end
|
178
|
+
|
179
|
+
File.foreach(file_name) do |line|
|
180
|
+
case line
|
181
|
+
when /^Start(\w+)/
|
182
|
+
section.push $1
|
183
|
+
next
|
184
|
+
when /^End(\w+)/
|
185
|
+
section.pop
|
186
|
+
next
|
237
187
|
end
|
238
|
-
|
239
|
-
|
188
|
+
|
189
|
+
case section
|
190
|
+
when ["FontMetrics", "CharMetrics"]
|
191
|
+
next unless line =~ /^CH?\s/
|
192
|
+
|
193
|
+
name = line[/\bN\s+(\.?\w+)\s*;/, 1]
|
194
|
+
@glyph_widths[name] = line[/\bWX\s+(\d+)\s*;/, 1].to_i
|
195
|
+
@bounding_boxes[name] = line[/\bB\s+([^;]+);/, 1].to_s.rstrip
|
196
|
+
when ["FontMetrics", "KernData", "KernPairs"]
|
197
|
+
next unless line =~ /^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/
|
198
|
+
@kern_pairs[[$1, $2]] = $3.to_i
|
199
|
+
when ["FontMetrics", "KernData", "TrackKern"],
|
200
|
+
["FontMetrics", "Composites"]
|
201
|
+
next
|
202
|
+
else
|
203
|
+
parse_generic_afm_attribute(line)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def parse_generic_afm_attribute(line)
|
209
|
+
line =~ /(^\w+)\s+(.*)/
|
210
|
+
key, value = $1.to_s.downcase, $2
|
211
|
+
|
212
|
+
@attributes[key] = @attributes[key] ?
|
213
|
+
Array(@attributes[key]) << value : value
|
214
|
+
end
|
240
215
|
end
|
241
216
|
|
242
217
|
class TTF < Metrics #:nodoc:
|
@@ -244,18 +219,18 @@ module Prawn
|
|
244
219
|
attr_accessor :ttf
|
245
220
|
|
246
221
|
def initialize(font)
|
247
|
-
@ttf = ::
|
222
|
+
@ttf = TTFunk::File.new(font)
|
248
223
|
@attributes = {}
|
249
224
|
@glyph_widths = {}
|
250
225
|
@bounding_boxes = {}
|
251
226
|
@char_widths = {}
|
252
|
-
@has_kerning_data =
|
227
|
+
@has_kerning_data = !! @ttf.kern? && @ttf.kern.sub_tables[0]
|
253
228
|
end
|
254
229
|
|
255
230
|
def cmap
|
256
|
-
@cmap ||=
|
231
|
+
@cmap ||= @ttf.cmap.formats[4]
|
257
232
|
end
|
258
|
-
|
233
|
+
|
259
234
|
def string_width(string, font_size, options = {})
|
260
235
|
scale = font_size / 1000.0
|
261
236
|
if options[:kerning]
|
@@ -298,9 +273,7 @@ module Prawn
|
|
298
273
|
i = r.is_a?(Array) ? r.pack("U*") : r
|
299
274
|
x = if i.is_a?(String)
|
300
275
|
unicode_codepoints = i.unpack("U*")
|
301
|
-
glyph_codes = unicode_codepoints.map { |u|
|
302
|
-
enc_table.get_glyph_id_for_unicode(u)
|
303
|
-
}
|
276
|
+
glyph_codes = unicode_codepoints.map { |u| cmap[u] }
|
304
277
|
glyph_codes.pack("n*")
|
305
278
|
else
|
306
279
|
i
|
@@ -313,7 +286,7 @@ module Prawn
|
|
313
286
|
def glyph_widths
|
314
287
|
glyphs = cmap.values.uniq.sort
|
315
288
|
first_glyph = glyphs.shift
|
316
|
-
widths = [first_glyph, [Integer(hmtx[first_glyph][0] * scale_factor)]]
|
289
|
+
widths = [first_glyph, [Integer(hmtx[first_glyph][0] * scale_factor)]]
|
317
290
|
prev_glyph = first_glyph
|
318
291
|
glyphs.each do |glyph|
|
319
292
|
unless glyph == prev_glyph + 1
|
@@ -327,38 +300,25 @@ module Prawn
|
|
327
300
|
end
|
328
301
|
|
329
302
|
def bbox
|
330
|
-
head = @ttf.get_table(:head)
|
331
303
|
[:x_min, :y_min, :x_max, :y_max].map do |atr|
|
332
|
-
Integer(head.send(atr)) * scale_factor
|
304
|
+
Integer(@ttf.head.send(atr)) * scale_factor
|
333
305
|
end
|
334
306
|
end
|
335
307
|
|
336
308
|
def ascender
|
337
|
-
Integer(@ttf.
|
309
|
+
Integer(@ttf.hhea.ascent * scale_factor)
|
338
310
|
end
|
339
311
|
|
340
312
|
def descender
|
341
|
-
Integer(@ttf.
|
313
|
+
Integer(@ttf.hhea.descent * scale_factor)
|
342
314
|
end
|
343
315
|
|
344
316
|
def line_gap
|
345
|
-
Integer(@ttf.
|
317
|
+
Integer(@ttf.hhea.line_gap * scale_factor)
|
346
318
|
end
|
347
319
|
|
348
320
|
def basename
|
349
|
-
|
350
|
-
ps_name = ::Font::TTF::Table::Name::NameRecord::POSTSCRIPT_NAME
|
351
|
-
|
352
|
-
@ttf.get_table(:name).name_records.each do |rec|
|
353
|
-
@basename = rec.utf8_str.to_sym if rec.name_id == ps_name
|
354
|
-
end
|
355
|
-
@basename
|
356
|
-
end
|
357
|
-
|
358
|
-
def enc_table
|
359
|
-
@enc_table ||= @ttf.get_table(:cmap).encoding_tables.find do |t|
|
360
|
-
t.class == ::Font::TTF::Table::Cmap::EncodingTable4
|
361
|
-
end
|
321
|
+
@basename ||= @ttf.name.postscript_name
|
362
322
|
end
|
363
323
|
|
364
324
|
# TODO: instead of creating a map that contains every glyph in the font,
|
@@ -375,20 +335,7 @@ module Prawn
|
|
375
335
|
end
|
376
336
|
|
377
337
|
def kern_pairs_table
|
378
|
-
|
379
|
-
|
380
|
-
table = @ttf.get_table(:kern).subtables.find { |s|
|
381
|
-
s.is_a? ::Font::TTF::Table::Kern::KerningSubtable0 }
|
382
|
-
|
383
|
-
if table
|
384
|
-
@kern_pairs_table = table.kerning_pairs.inject({}) do |h,p|
|
385
|
-
h[[p.left, p.right]] = p.value; h
|
386
|
-
end
|
387
|
-
else
|
388
|
-
@kern_pairs_table = {}
|
389
|
-
end
|
390
|
-
rescue ::Font::TTF::TableMissing
|
391
|
-
@kern_pairs_table = {}
|
338
|
+
@kerning_data ||= has_kerning_data? ? @ttf.kern.sub_tables[0] : {}
|
392
339
|
end
|
393
340
|
|
394
341
|
def has_kerning_data?
|
@@ -404,18 +351,16 @@ module Prawn
|
|
404
351
|
if options[:kerning]
|
405
352
|
kern(text)
|
406
353
|
else
|
407
|
-
|
408
|
-
glyph_codes = unicode_codepoints.map { |u|
|
409
|
-
enc_table.get_glyph_id_for_unicode(u)
|
410
|
-
}
|
354
|
+
unicode_codepoints = text.unpack("U*")
|
355
|
+
glyph_codes = unicode_codepoints.map { |u| cmap[u] }
|
411
356
|
text = glyph_codes.pack("n*")
|
412
357
|
end
|
413
358
|
end
|
414
|
-
|
359
|
+
|
415
360
|
private
|
416
361
|
|
417
362
|
def hmtx
|
418
|
-
@hmtx ||= @ttf.
|
363
|
+
@hmtx ||= @ttf.hmtx.values
|
419
364
|
end
|
420
365
|
|
421
366
|
def character_width_by_code(code)
|
@@ -424,7 +369,7 @@ module Prawn
|
|
424
369
|
end
|
425
370
|
|
426
371
|
def scale_factor
|
427
|
-
@scale ||= 1000 * Float(@ttf.
|
372
|
+
@scale ||= 1000 * Float(@ttf.head.units_per_em)**-1
|
428
373
|
end
|
429
374
|
|
430
375
|
end
|
data/lib/prawn/graphics.rb
CHANGED
@@ -7,25 +7,25 @@
|
|
7
7
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
8
|
|
9
9
|
require "enumerator"
|
10
|
-
require "prawn/graphics/cell"
|
10
|
+
require "prawn/graphics/cell"
|
11
11
|
require "prawn/graphics/color"
|
12
12
|
|
13
13
|
module Prawn
|
14
14
|
|
15
|
-
# Implements the drawing facilities for Prawn::Document.
|
15
|
+
# Implements the drawing facilities for Prawn::Document.
|
16
16
|
# Use this to draw the most beautiful imaginable things.
|
17
|
-
#
|
17
|
+
#
|
18
18
|
# This file lifts and modifies several of PDF::Writer's graphics functions
|
19
19
|
# ruby-pdf.rubyforge.org
|
20
20
|
#
|
21
|
-
module Graphics
|
22
|
-
|
21
|
+
module Graphics
|
22
|
+
|
23
23
|
include Color
|
24
|
-
|
24
|
+
|
25
25
|
#######################################################################
|
26
26
|
# Low level drawing operations must translate to absolute coords! #
|
27
27
|
#######################################################################
|
28
|
-
|
28
|
+
|
29
29
|
# Moves the drawing position to a given point. The point can be
|
30
30
|
# specified as a tuple or a flattened argument list
|
31
31
|
#
|
@@ -33,50 +33,50 @@ module Prawn
|
|
33
33
|
# pdf.move_to(100,50)
|
34
34
|
#
|
35
35
|
def move_to(*point)
|
36
|
-
x,y = translate(point)
|
36
|
+
x,y = translate(point)
|
37
37
|
add_content("%.3f %.3f m" % [ x, y ])
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
# Draws a line from the current drawing position to the specified point.
|
41
|
-
# The destination may be described as a tuple or a flattened list:
|
41
|
+
# The destination may be described as a tuple or a flattened list:
|
42
42
|
#
|
43
|
-
# pdf.line_to [50,50]
|
44
|
-
# pdf.line_to(50,50)
|
43
|
+
# pdf.line_to [50,50]
|
44
|
+
# pdf.line_to(50,50)
|
45
45
|
#
|
46
|
-
def line_to(*point)
|
46
|
+
def line_to(*point)
|
47
47
|
x,y = translate(point)
|
48
|
-
add_content("%.3f %.3f l" % [ x, y ])
|
49
|
-
end
|
50
|
-
|
51
|
-
# Draws a Bezier curve from the current drawing position to the
|
48
|
+
add_content("%.3f %.3f l" % [ x, y ])
|
49
|
+
end
|
50
|
+
|
51
|
+
# Draws a Bezier curve from the current drawing position to the
|
52
52
|
# specified point, bounded by two additional points.
|
53
|
-
#
|
54
|
-
# pdf.curve_to [100,100], :bounds => [[90,90],[75,75]]
|
55
53
|
#
|
56
|
-
|
57
|
-
|
54
|
+
# pdf.curve_to [100,100], :bounds => [[90,90],[75,75]]
|
55
|
+
#
|
56
|
+
def curve_to(dest,options={})
|
57
|
+
options[:bounds] or raise Prawn::Errors::InvalidGraphicsPath,
|
58
58
|
"Bounding points for bezier curve must be specified "+
|
59
|
-
"as :bounds => [[x1,y1],[x2,y2]]"
|
59
|
+
"as :bounds => [[x1,y1],[x2,y2]]"
|
60
60
|
|
61
61
|
curve_points = (options[:bounds] << dest).map { |e| translate(e) }
|
62
|
-
add_content("%.3f %.3f %.3f %.3f %.3f %.3f c" %
|
63
|
-
curve_points.flatten )
|
64
|
-
end
|
65
|
-
|
66
|
-
# Draws a rectangle given <tt>point</tt>, <tt>width</tt> and
|
62
|
+
add_content("%.3f %.3f %.3f %.3f %.3f %.3f c" %
|
63
|
+
curve_points.flatten )
|
64
|
+
end
|
65
|
+
|
66
|
+
# Draws a rectangle given <tt>point</tt>, <tt>width</tt> and
|
67
67
|
# <tt>height</tt>. The rectangle is bounded by its upper-left corner.
|
68
68
|
#
|
69
69
|
# pdf.rectangle [300,300], 100, 200
|
70
|
-
#
|
70
|
+
#
|
71
71
|
def rectangle(point,width,height)
|
72
72
|
x,y = translate(point)
|
73
|
-
add_content("%.3f %.3f %.3f %.3f re" % [ x, y - height, width, height ])
|
73
|
+
add_content("%.3f %.3f %.3f %.3f re" % [ x, y - height, width, height ])
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
###########################################################
|
77
|
-
# Higher level functions: May use relative coords #
|
78
|
-
###########################################################
|
79
|
-
|
77
|
+
# Higher level functions: May use relative coords #
|
78
|
+
###########################################################
|
79
|
+
|
80
80
|
# Sets line thickness to the <tt>width</tt> specified.
|
81
81
|
#
|
82
82
|
def line_width=(width)
|
@@ -93,24 +93,33 @@ module Prawn
|
|
93
93
|
@line_width || 1
|
94
94
|
end
|
95
95
|
end
|
96
|
-
|
97
|
-
# Draws a line from one point to another. Points may be specified as
|
96
|
+
|
97
|
+
# Draws a line from one point to another. Points may be specified as
|
98
98
|
# tuples or flattened argument list:
|
99
99
|
#
|
100
|
-
# pdf.line [100,100], [200,250]
|
100
|
+
# pdf.line [100,100], [200,250]
|
101
101
|
# pdf.line(100,100,200,250)
|
102
102
|
#
|
103
103
|
def line(*points)
|
104
104
|
x0,y0,x1,y1 = points.flatten
|
105
105
|
move_to(x0, y0)
|
106
106
|
line_to(x1, y1)
|
107
|
-
end
|
107
|
+
end
|
108
108
|
|
109
109
|
# Draws a horizontal line from <tt>x1</tt> to <tt>x2</tt> at the
|
110
|
-
# current <tt>y</tt> position.
|
110
|
+
# current <tt>y</tt> position, or the position specified by the :at option.
|
111
111
|
#
|
112
|
-
|
113
|
-
|
112
|
+
# # draw a line from [25, 75] to [100, 75]
|
113
|
+
# horizontal_line 25, 100, :at => 75
|
114
|
+
#
|
115
|
+
def horizontal_line(x1,x2,options={})
|
116
|
+
if options[:at]
|
117
|
+
y1 = options[:at]
|
118
|
+
else
|
119
|
+
y1 = y - bounds.absolute_bottom
|
120
|
+
end
|
121
|
+
|
122
|
+
line(x1,y1,x2,y1)
|
114
123
|
end
|
115
124
|
|
116
125
|
# Draws a horizontal line from the left border to the right border of the
|
@@ -120,115 +129,124 @@ module Prawn
|
|
120
129
|
horizontal_line(bounds.left, bounds.right)
|
121
130
|
end
|
122
131
|
|
123
|
-
# Draws a vertical line at the given
|
124
|
-
#
|
125
|
-
|
126
|
-
|
132
|
+
# Draws a vertical line at the x cooordinate given by :at from y1 to y2.
|
133
|
+
#
|
134
|
+
# # draw a line from [25, 100] to [25, 300]
|
135
|
+
# vertical_line 100, 300, :at => 25
|
136
|
+
#
|
137
|
+
def vertical_line(y1,y2,params)
|
138
|
+
line(params[:at],y1,params[:at],y2)
|
127
139
|
end
|
128
|
-
|
140
|
+
|
129
141
|
# Draws a Bezier curve between two points, bounded by two additional
|
130
142
|
# points
|
131
143
|
#
|
132
|
-
# pdf.curve [50,100], [100,100], :bounds => [[90,90],[75,75]]
|
144
|
+
# pdf.curve [50,100], [100,100], :bounds => [[90,90],[75,75]]
|
133
145
|
#
|
134
146
|
def curve(origin,dest, options={})
|
135
|
-
move_to
|
147
|
+
move_to(*origin)
|
136
148
|
curve_to(dest,options)
|
137
149
|
end
|
138
150
|
|
139
151
|
# This constant is used to approximate a symmetrical arc using a cubic
|
140
|
-
# Bezier curve.
|
152
|
+
# Bezier curve.
|
141
153
|
#
|
142
154
|
KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0)
|
143
|
-
|
155
|
+
|
144
156
|
# Draws a circle of radius <tt>:radius</tt> with the centre-point at <tt>point</tt>
|
145
157
|
# as a complete subpath. The drawing point will be moved to the
|
146
|
-
# centre-point upon completion of the drawing the circle.
|
147
|
-
#
|
148
|
-
# pdf.circle_at [100,100], :radius => 25
|
158
|
+
# centre-point upon completion of the drawing the circle.
|
159
|
+
#
|
160
|
+
# pdf.circle_at [100,100], :radius => 25
|
149
161
|
#
|
150
|
-
def circle_at(point, options)
|
162
|
+
def circle_at(point, options)
|
151
163
|
x,y = point
|
152
|
-
ellipse_at [x, y], options[:radius]
|
153
|
-
end
|
154
|
-
|
164
|
+
ellipse_at [x, y], options[:radius]
|
165
|
+
end
|
166
|
+
|
155
167
|
# Draws an ellipse of +x+ radius <tt>r1</tt> and +y+ radius <tt>r2</tt>
|
156
168
|
# with the centre-point at <tt>point</tt> as a complete subpath. The
|
157
169
|
# drawing point will be moved to the centre-point upon completion of the
|
158
|
-
# drawing the ellipse.
|
159
|
-
#
|
170
|
+
# drawing the ellipse.
|
171
|
+
#
|
160
172
|
# # draws an ellipse with x-radius 25 and y-radius 50
|
161
|
-
# pdf.ellipse_at [100,100], 25, 50
|
173
|
+
# pdf.ellipse_at [100,100], 25, 50
|
162
174
|
#
|
163
|
-
def ellipse_at(point, r1, r2 = r1)
|
175
|
+
def ellipse_at(point, r1, r2 = r1)
|
164
176
|
x, y = point
|
165
177
|
l1 = r1 * KAPPA
|
166
|
-
l2 = r2 * KAPPA
|
167
|
-
|
178
|
+
l2 = r2 * KAPPA
|
179
|
+
|
168
180
|
move_to(x + r1, y)
|
169
|
-
|
181
|
+
|
170
182
|
# Upper right hand corner
|
171
|
-
curve_to [x, y + r2],
|
183
|
+
curve_to [x, y + r2],
|
172
184
|
:bounds => [[x + r1, y + l1], [x + l2, y + r2]]
|
173
185
|
|
174
|
-
# Upper left hand corner
|
175
|
-
curve_to [x - r1, y],
|
176
|
-
:bounds => [[x - l2, y + r2], [x - r1, y + l1]]
|
177
|
-
|
186
|
+
# Upper left hand corner
|
187
|
+
curve_to [x - r1, y],
|
188
|
+
:bounds => [[x - l2, y + r2], [x - r1, y + l1]]
|
189
|
+
|
178
190
|
# Lower left hand corner
|
179
|
-
curve_to [x, y - r2],
|
180
|
-
:bounds => [[x - r1, y - l1], [x - l2, y - r2]]
|
191
|
+
curve_to [x, y - r2],
|
192
|
+
:bounds => [[x - r1, y - l1], [x - l2, y - r2]]
|
181
193
|
|
182
194
|
# Lower right hand corner
|
183
195
|
curve_to [x + r1, y],
|
184
|
-
:bounds => [[x + l2, y - r2], [x + r1, y - l1]]
|
185
|
-
|
196
|
+
:bounds => [[x + l2, y - r2], [x + r1, y - l1]]
|
197
|
+
|
186
198
|
move_to(x, y)
|
187
199
|
end
|
188
|
-
|
200
|
+
|
189
201
|
# Draws a polygon from the specified points.
|
190
|
-
#
|
202
|
+
#
|
191
203
|
# # draws a snazzy triangle
|
192
|
-
# pdf.polygon [100,100], [100,200], [200,200]
|
204
|
+
# pdf.polygon [100,100], [100,200], [200,200]
|
193
205
|
#
|
194
|
-
def polygon(*points)
|
206
|
+
def polygon(*points)
|
195
207
|
move_to points[0]
|
196
208
|
(points << points[0]).each_cons(2) do |p1,p2|
|
197
209
|
line_to(*p2)
|
198
210
|
end
|
199
211
|
end
|
200
|
-
|
212
|
+
|
201
213
|
# Strokes and closes the current path. See Graphic::Color for color details
|
202
214
|
#
|
203
215
|
def stroke
|
204
216
|
yield if block_given?
|
205
217
|
add_content "S"
|
206
218
|
end
|
219
|
+
|
220
|
+
# Draws and strokes a rectangle represented by the current bounding box
|
221
|
+
#
|
222
|
+
def stroke_bounds
|
223
|
+
stroke_rectangle bounds.top_left, bounds.width, bounds.height
|
224
|
+
end
|
207
225
|
|
208
226
|
# Fills and closes the current path. See Graphic::Color for color details
|
209
227
|
#
|
210
|
-
def fill
|
228
|
+
def fill
|
211
229
|
yield if block_given?
|
212
230
|
add_content "f"
|
213
231
|
end
|
214
232
|
|
215
233
|
# Fills, strokes, and closes the current path. See Graphic::Color for color details
|
216
234
|
#
|
217
|
-
def fill_and_stroke
|
235
|
+
def fill_and_stroke
|
218
236
|
yield if block_given?
|
219
|
-
add_content "b"
|
220
|
-
end
|
221
|
-
|
222
|
-
private
|
223
|
-
|
237
|
+
add_content "b"
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
224
242
|
def translate(*point)
|
225
243
|
x,y = point.flatten
|
226
244
|
[@bounding_box.absolute_left + x, @bounding_box.absolute_bottom + y]
|
227
|
-
end
|
228
|
-
|
245
|
+
end
|
246
|
+
|
229
247
|
def translate!(point)
|
230
248
|
point.replace(translate(point))
|
231
|
-
end
|
249
|
+
end
|
232
250
|
|
233
251
|
end
|
234
252
|
end
|