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.
Files changed (144) hide show
  1. data/README +6 -10
  2. data/Rakefile +4 -13
  3. data/data/encodings/win_ansi.txt +29 -0
  4. data/data/images/fractal.jpg +0 -0
  5. data/data/images/letterhead.jpg +0 -0
  6. data/examples/bounding_box/bounding_boxes.rb +44 -0
  7. data/examples/bounding_box/lazy_bounding_boxes.rb +28 -0
  8. data/examples/bounding_box/padded_box.rb +24 -0
  9. data/examples/{russian_boxes.rb → bounding_box/russian_boxes.rb} +9 -6
  10. data/examples/general/background.rb +20 -0
  11. data/examples/{canvas.rb → general/canvas.rb} +6 -2
  12. data/examples/general/measurement_units.rb +52 -0
  13. data/examples/{multi_page_layout.rb → general/multi_page_layout.rb} +6 -3
  14. data/examples/{page_geometry.rb → general/page_geometry.rb} +6 -2
  15. data/examples/{image.rb → graphics/basic_images.rb} +8 -4
  16. data/examples/graphics/cmyk.rb +13 -0
  17. data/examples/graphics/curves.rb +12 -0
  18. data/examples/{hexagon.rb → graphics/hexagon.rb} +5 -5
  19. data/examples/graphics/image_fit.rb +16 -0
  20. data/examples/graphics/image_flow.rb +38 -0
  21. data/examples/graphics/image_position.rb +18 -0
  22. data/examples/{line.rb → graphics/line.rb} +4 -2
  23. data/examples/{png_types.rb → graphics/png_types.rb} +4 -4
  24. data/examples/{polygons.rb → graphics/polygons.rb} +5 -4
  25. data/examples/graphics/remote_images.rb +12 -0
  26. data/examples/{ruport_helpers.rb → graphics/ruport_style_helpers.rb} +8 -5
  27. data/examples/graphics/stroke_bounds.rb +23 -0
  28. data/examples/{chinese_text_wrapping.rb → m17n/chinese_text_wrapping.rb} +7 -4
  29. data/examples/m17n/euro.rb +16 -0
  30. data/examples/m17n/sjis.rb +29 -0
  31. data/examples/m17n/utf8.rb +14 -0
  32. data/examples/m17n/win_ansi_charset.rb +55 -0
  33. data/examples/{addressbook.csv → table/addressbook.csv} +0 -0
  34. data/examples/{cell.rb → table/cell.rb} +8 -6
  35. data/examples/{currency.csv → table/currency.csv} +0 -0
  36. data/examples/{fancy_table.rb → table/fancy_table.rb} +9 -6
  37. data/examples/{ruport_formatter.rb → table/ruport_formatter.rb} +6 -3
  38. data/examples/{table.rb → table/table.rb} +6 -2
  39. data/examples/table/table_alignment.rb +18 -0
  40. data/examples/table/table_border_color.rb +17 -0
  41. data/examples/table/table_colspan.rb +19 -0
  42. data/examples/table/table_header_color.rb +19 -0
  43. data/examples/table/table_header_underline.rb +15 -0
  44. data/examples/{alignment.rb → text/alignment.rb} +5 -2
  45. data/examples/text/family_based_styling.rb +25 -0
  46. data/examples/{flowing_text_with_header_and_footer.rb → text/flowing_text_with_header_and_footer.rb} +19 -8
  47. data/examples/text/font_calculations.rb +91 -0
  48. data/examples/text/font_size.rb +34 -0
  49. data/examples/{kerning.rb → text/kerning.rb} +5 -1
  50. data/examples/text/simple_text.rb +18 -0
  51. data/examples/text/simple_text_ttf.rb +18 -0
  52. data/examples/{span.rb → text/span.rb} +5 -2
  53. data/examples/text/text_box.rb +26 -0
  54. data/examples/{text_flow.rb → text/text_flow.rb} +5 -2
  55. data/lib/prawn.rb +26 -20
  56. data/lib/prawn/compatibility.rb +5 -8
  57. data/lib/prawn/document.rb +29 -13
  58. data/lib/prawn/document/annotations.rb +63 -0
  59. data/lib/prawn/document/bounding_box.rb +18 -3
  60. data/lib/prawn/document/destinations.rb +81 -0
  61. data/lib/prawn/document/internals.rb +16 -2
  62. data/lib/prawn/document/page_geometry.rb +58 -57
  63. data/lib/prawn/document/span.rb +8 -0
  64. data/lib/prawn/document/table.rb +81 -31
  65. data/lib/prawn/document/text.rb +66 -21
  66. data/lib/prawn/document/text/box.rb +77 -0
  67. data/lib/prawn/encoding.rb +121 -0
  68. data/lib/prawn/errors.rb +4 -0
  69. data/lib/prawn/font.rb +70 -42
  70. data/lib/prawn/font/metrics.rb +64 -119
  71. data/lib/prawn/graphics.rb +105 -87
  72. data/lib/prawn/graphics/cell.rb +55 -28
  73. data/lib/prawn/graphics/color.rb +8 -0
  74. data/lib/prawn/images.rb +55 -12
  75. data/lib/prawn/images/jpg.rb +2 -1
  76. data/lib/prawn/images/png.rb +2 -1
  77. data/lib/prawn/literal_string.rb +14 -0
  78. data/lib/prawn/measurement_extensions.rb +46 -0
  79. data/lib/prawn/measurements.rb +71 -0
  80. data/lib/prawn/name_tree.rb +165 -0
  81. data/lib/prawn/pdf_object.rb +8 -1
  82. data/spec/annotations_spec.rb +90 -0
  83. data/spec/destinations_spec.rb +15 -0
  84. data/spec/document_spec.rb +39 -2
  85. data/spec/font_spec.rb +22 -0
  86. data/spec/graphics_spec.rb +99 -87
  87. data/spec/images_spec.rb +29 -1
  88. data/spec/measurement_units_spec.rb +23 -0
  89. data/spec/metrics_spec.rb +3 -2
  90. data/spec/name_tree_spec.rb +103 -0
  91. data/spec/pdf_object_spec.rb +15 -5
  92. data/spec/png_spec.rb +14 -14
  93. data/spec/spec_helper.rb +8 -6
  94. data/spec/table_spec.rb +40 -0
  95. data/spec/text_spec.rb +6 -4
  96. data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
  97. data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
  98. data/vendor/ttfunk/example.rb +5 -0
  99. data/vendor/ttfunk/lib/ttfunk.rb +48 -0
  100. data/vendor/ttfunk/lib/ttfunk/table.rb +27 -0
  101. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +94 -0
  102. data/vendor/ttfunk/lib/ttfunk/table/directory.rb +25 -0
  103. data/vendor/ttfunk/lib/ttfunk/table/head.rb +25 -0
  104. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +27 -0
  105. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +20 -0
  106. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +48 -0
  107. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +17 -0
  108. data/vendor/ttfunk/lib/ttfunk/table/name.rb +52 -0
  109. metadata +93 -62
  110. data/examples/bounding_boxes.rb +0 -30
  111. data/examples/curves.rb +0 -10
  112. data/examples/family_based_styling.rb +0 -21
  113. data/examples/font_size.rb +0 -19
  114. data/examples/image2.rb +0 -13
  115. data/examples/image_flow.rb +0 -29
  116. data/examples/lazy_bounding_boxes.rb +0 -19
  117. data/examples/remote_images.rb +0 -7
  118. data/examples/simple_text.rb +0 -15
  119. data/examples/simple_text_ttf.rb +0 -16
  120. data/examples/sjis.rb +0 -21
  121. data/examples/utf8.rb +0 -12
  122. data/vendor/font_ttf/ttf.rb +0 -20
  123. data/vendor/font_ttf/ttf/datatypes.rb +0 -189
  124. data/vendor/font_ttf/ttf/encodings.rb +0 -140
  125. data/vendor/font_ttf/ttf/exceptions.rb +0 -28
  126. data/vendor/font_ttf/ttf/file.rb +0 -290
  127. data/vendor/font_ttf/ttf/fontchunk.rb +0 -77
  128. data/vendor/font_ttf/ttf/table/cmap.rb +0 -408
  129. data/vendor/font_ttf/ttf/table/cvt.rb +0 -49
  130. data/vendor/font_ttf/ttf/table/fpgm.rb +0 -48
  131. data/vendor/font_ttf/ttf/table/gasp.rb +0 -88
  132. data/vendor/font_ttf/ttf/table/glyf.rb +0 -452
  133. data/vendor/font_ttf/ttf/table/head.rb +0 -86
  134. data/vendor/font_ttf/ttf/table/hhea.rb +0 -96
  135. data/vendor/font_ttf/ttf/table/hmtx.rb +0 -98
  136. data/vendor/font_ttf/ttf/table/kern.rb +0 -186
  137. data/vendor/font_ttf/ttf/table/loca.rb +0 -75
  138. data/vendor/font_ttf/ttf/table/maxp.rb +0 -81
  139. data/vendor/font_ttf/ttf/table/name.rb +0 -222
  140. data/vendor/font_ttf/ttf/table/os2.rb +0 -172
  141. data/vendor/font_ttf/ttf/table/post.rb +0 -120
  142. data/vendor/font_ttf/ttf/table/prep.rb +0 -27
  143. data/vendor/font_ttf/ttf/table/vhea.rb +0 -45
  144. data/vendor/font_ttf/ttf/table/vmtx.rb +0 -36
@@ -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
- # String *must* be encoded as iso-8859-1
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 iso-8859-1
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| ISOLatin1Encoding.index(n) }] = p[1]
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[ISOLatin1Encoding[i]].to_i
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 iso-8859-1
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(file)
176
+ def parse_afm(file_name)
203
177
  section = []
204
-
205
- File.open(file,"rb") do |file|
206
-
207
- file.each do |line|
208
- if line =~ /^Start(\w+)/
209
- section.push $1
210
- next
211
- elsif line =~ /^End(\w+)/
212
- section.pop
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
- end
239
- end
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 = ::Font::TTF::File.open(font,"rb")
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 = !kern_pairs_table.empty?
227
+ @has_kerning_data = !! @ttf.kern? && @ttf.kern.sub_tables[0]
253
228
  end
254
229
 
255
230
  def cmap
256
- @cmap ||= enc_table.charmaps
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.get_table(:hhea).ascender * scale_factor)
309
+ Integer(@ttf.hhea.ascent * scale_factor)
338
310
  end
339
311
 
340
312
  def descender
341
- Integer(@ttf.get_table(:hhea).descender * scale_factor)
313
+ Integer(@ttf.hhea.descent * scale_factor)
342
314
  end
343
315
 
344
316
  def line_gap
345
- Integer(@ttf.get_table(:hhea).line_gap * scale_factor)
317
+ Integer(@ttf.hhea.line_gap * scale_factor)
346
318
  end
347
319
 
348
320
  def basename
349
- return @basename if @basename
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
- return @kern_pairs_table if @kern_pairs_table
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
- unicode_codepoints = text.unpack("U*")
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.get_table(:hmtx).metrics
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.get_table(:head).units_per_em)**-1
372
+ @scale ||= 1000 * Float(@ttf.head.units_per_em)**-1
428
373
  end
429
374
 
430
375
  end
@@ -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
- def curve_to(dest,options={})
57
- options[:bounds] or raise Prawn::Errors::InvalidGraphicsPath,
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
- def horizontal_line(x1,x2)
113
- line(x1,y-bounds.absolute_bottom,x2,y-bounds.absolute_bottom)
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 x position from y1 to y2.
124
- #
125
- def vertical_line_at(x,y1,y2)
126
- line(x,y1,x,y2)
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 *origin
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