prawn-core 0.6.3 → 0.7.1

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 (43) hide show
  1. data/Rakefile +1 -1
  2. data/examples/general/context_sensitive_headers.rb +37 -0
  3. data/examples/general/float.rb +11 -0
  4. data/examples/general/repeaters.rb +43 -0
  5. data/examples/m17n/chinese_text_wrapping.rb +1 -3
  6. data/examples/text/font_calculations.rb +6 -6
  7. data/examples/text/text_box.rb +80 -17
  8. data/lib/prawn/core.rb +3 -1
  9. data/lib/prawn/document/bounding_box.rb +9 -0
  10. data/lib/prawn/document/column_box.rb +13 -2
  11. data/lib/prawn/document/internals.rb +21 -3
  12. data/lib/prawn/document/snapshot.rb +7 -2
  13. data/lib/prawn/document/span.rb +3 -3
  14. data/lib/prawn/document.rb +78 -19
  15. data/lib/prawn/font/afm.rb +10 -7
  16. data/lib/prawn/font/ttf.rb +6 -4
  17. data/lib/prawn/font.rb +34 -24
  18. data/lib/prawn/graphics/cap_style.rb +5 -2
  19. data/lib/prawn/graphics/color.rb +117 -57
  20. data/lib/prawn/graphics/dash.rb +4 -2
  21. data/lib/prawn/graphics/join_style.rb +6 -3
  22. data/lib/prawn/graphics/transparency.rb +65 -18
  23. data/lib/prawn/images/jpg.rb +1 -1
  24. data/lib/prawn/images/png.rb +1 -1
  25. data/lib/prawn/object_store.rb +30 -1
  26. data/lib/prawn/reference.rb +25 -3
  27. data/lib/prawn/repeater.rb +117 -0
  28. data/lib/prawn/stamp.rb +102 -40
  29. data/lib/prawn/text/box.rb +344 -0
  30. data/lib/prawn/text.rb +255 -0
  31. data/spec/document_spec.rb +125 -4
  32. data/spec/object_store_spec.rb +33 -0
  33. data/spec/repeater_spec.rb +79 -0
  34. data/spec/stamp_spec.rb +8 -0
  35. data/spec/text_box_spec.rb +282 -69
  36. data/spec/text_spec.rb +49 -29
  37. data/spec/transparency_spec.rb +14 -0
  38. data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +2 -2
  39. metadata +158 -155
  40. data/examples/general/measurement_units.pdf +0 -4667
  41. data/lib/prawn/document/text/box.rb +0 -90
  42. data/lib/prawn/document/text/wrapping.rb +0 -62
  43. data/lib/prawn/document/text.rb +0 -184
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'rake/testtask'
4
4
  require "rake/rdoctask"
5
5
  require "rake/gempackagetask"
6
6
 
7
- PRAWN_VERSION = "0.6.3"
7
+ PRAWN_VERSION = "0.7.1"
8
8
 
9
9
  task :default => [:test]
10
10
 
@@ -0,0 +1,37 @@
1
+ require "#{File.dirname(__FILE__)}/../example_helper.rb"
2
+
3
+ # Ex. Generate a roster of meeting attendees given a set of meetings.
4
+ # Attendees for a meeting may overflow to accross page boundaries but
5
+ # each meeting starts on a separate page. Each page for any given
6
+ # meeting will have the heading for that meeting.
7
+
8
+ #dummying up some meetings
9
+ meetings = []
10
+ 5.times do |i|
11
+ meetings << "Meeting number #{i}"
12
+ end
13
+
14
+ Prawn::Document.generate('context_sensitive_headers.pdf', :margin => [100, 100], :skip_page_creation => true) do
15
+ meetings.each_with_index do |meeting,i|
16
+
17
+ create_stamp(meeting.to_s) do
18
+ canvas do
19
+ text_box("header for #{meeting}",
20
+ :at => [bounds.left + 50, bounds.top - 20],
21
+ :height => 50,
22
+ :width => margin_box.width)
23
+ end
24
+ end
25
+ on_page_create { stamp(meeting.to_s) }
26
+
27
+ start_new_page
28
+
29
+ #simulate some meetings with content over multiple pages
30
+ (15 + 20*i).times do |i|
31
+ text "#{meeting} attendee #{i}"
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
@@ -0,0 +1,11 @@
1
+ require "#{File.dirname(__FILE__)}/../example_helper"
2
+
3
+ Prawn::Document.generate('float.pdf') do
4
+ float do
5
+ bounding_box [bounds.width / 2.0, bounds.top], :width => 100 do
6
+ text "Hello world. " * 50
7
+ end
8
+ end
9
+
10
+ text "Hello world again"
11
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This example demonstrates how to make use of Prawn's repeating element
4
+ # support. Note that all repeated elements are generated using XObjects, so
5
+ # they should be pretty efficient.
6
+ #
7
+ #
8
+ require "#{File.dirname(__FILE__)}/../example_helper.rb"
9
+
10
+ Prawn::Document.generate("repeat.pdf", :skip_page_creation => true) do
11
+
12
+ repeat :all do
13
+ text "ALLLLLL", :at => bounds.top_left
14
+ end
15
+
16
+ repeat :odd do
17
+ text "ODD", :at => [0,0]
18
+ end
19
+
20
+ repeat :even do
21
+ text "EVEN", :at => [0,0]
22
+ end
23
+
24
+ repeat [1,2] do
25
+ text "[1,2]", :at => [100,0]
26
+ end
27
+
28
+ repeat 2..4 do
29
+ text "2..4", :at => [200,0]
30
+ end
31
+
32
+ repeat(lambda { |pg| pg % 3 == 0 }) do
33
+ text "Every third", :at => [250, 20]
34
+ end
35
+
36
+ 10.times do
37
+ start_new_page
38
+ text "A wonderful page", :at => [400,400]
39
+ end
40
+
41
+ end
42
+
43
+
@@ -1,7 +1,5 @@
1
1
  # encoding: utf-8
2
2
  #
3
- # Some text is not usefully wrapped by our naive_wrap which depends on
4
- # spaces. This example shows how to wrap by character instead.
5
3
  #
6
4
  require "#{File.dirname(__FILE__)}/../example_helper.rb"
7
5
 
@@ -11,7 +9,7 @@ Prawn::Document.generate("chinese_flow.pdf") do
11
9
  font_size 16
12
10
 
13
11
  long_text = "更可怕的是,同质化竞争对手可以按照URL中后面这个ID来遍历您的DB中的内容,写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事,这样的话,你就非常被动了。写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事写个小爬虫把你的页面上的关键信息顺次爬下来也不是什么难事"
14
- text long_text, :wrap => :character
12
+ text long_text
15
13
 
16
14
  # be sure to restore space based wrapping when dealing with latin scripts
17
15
  long_text = "Text with some spaces " * 25
@@ -64,17 +64,17 @@ Prawn::Document.generate('font_calculations.pdf') do
64
64
  stroke_line [0, bl + font.ascender], [bounds.width, bl + font.ascender]
65
65
 
66
66
  stroke_color colors[:descender]
67
- stroke_line [0,bl], [0, bl + font.descender]
68
- stroke_line [0, bl + font.descender], [bounds.width, bl + font.descender]
67
+ stroke_line [0,bl], [0, bl - font.descender]
68
+ stroke_line [0, bl - font.descender], [bounds.width, bl - font.descender]
69
69
 
70
70
  stroke_color colors[:line_gap]
71
- stroke_line [0, bl + font.descender], [0,bl + font.descender - font.line_gap]
72
- stroke_line [0, bl + font.descender - font.line_gap],
73
- [bounds.width,bl + font.descender - font.line_gap]
71
+ stroke_line [0, bl - font.descender], [0,bl - font.descender - font.line_gap]
72
+ stroke_line [0, bl - font.descender - font.line_gap],
73
+ [bounds.width,bl - font.descender - font.line_gap]
74
74
 
75
75
  stroke_color colors[:font_height]
76
76
  stroke_line [bounds.width, bl + font.ascender],
77
- [bounds.width, bl + font.descender - font.line_gap]
77
+ [bounds.width, bl - font.descender - font.line_gap]
78
78
 
79
79
  stroke_color "000000"
80
80
  fill_color "000000"
@@ -1,25 +1,88 @@
1
1
  # encoding: utf-8
2
2
  #
3
- # A text box is positioned by a top-left corner, width, and height and is
4
- # essentially an invisible rectangle that the text will flow within. If the
5
- # text exceeds the boundaries, it is either truncated, replaced with some
6
- # ellipses, or set to expand beyond the bottom boundary.
7
- #
8
- require "#{File.dirname(__FILE__)}/../example_helper.rb"
9
3
 
10
- Prawn::Document.generate("text_box.pdf") do
4
+ require 'examples/example_helper'
11
5
 
12
- text_box "Oh hai text box. " * 200,
13
- :width => 300, :height => font.height * 5,
14
- :overflow => :ellipses,
15
- :at => [100,bounds.top]
6
+ Prawn::Document.generate("text_box.pdf") do
7
+ def get_string(i, j)
8
+ case i
9
+ when 0
10
+ text = "this is left text " * 30
11
+ text.insert(48, "\n\n")
12
+ when 1
13
+ text = "this is center text " * 30
14
+ text.insert(54, "\n\n")
15
+ when 2
16
+ text = "this is right text " * 30
17
+ text.insert(51, "\n\n")
18
+ end
19
+
20
+ case j
21
+ when 0
22
+ text.split(" ").slice(0..47).join(" ")
23
+ when 3
24
+ text.delete(" ")
25
+ else
26
+ text
27
+ end
28
+ end
16
29
 
17
- text_box "Oh hai text box. " * 200,
18
- :width => 250, :height => font.height * 10,
19
- :overflow => :truncate,
20
- :at => [50, 300]
30
+ def get_options(i, j)
31
+ options = {
32
+ :width => bounds.width * 0.3,
33
+ :height => bounds.width * 0.3,
34
+ :overflow => :ellipses,
35
+ :at => [0, 0],
36
+ :align => :left,
37
+ :document => self
38
+ }
39
+
40
+ case i
41
+ when 0
42
+ options[:valign] = :top if j == 0
43
+ when 1
44
+ options[:align] = :center
45
+ options[:valign] = :center if j == 0
46
+ when 2
47
+ options[:align] = :right
48
+ options[:valign] = :bottom if j == 0
49
+ end
50
+
51
+ case j
52
+ when 1
53
+ options[:overflow] = :shrink_to_fit
54
+ when 2
55
+ options[:leading] = font.height * 0.5
56
+ options[:overflow] = :truncate
57
+ end
58
+ options
59
+ end
21
60
 
22
- move_down 20
61
+ stroke_color("555555")
62
+ 3.times do |i|
63
+ 4.times do |j|
64
+ options = get_options(i, j)
65
+ options[:at][0] = (bounds.width - options[:width]) * 0.5 * i
66
+ options[:at][1] = bounds.top - (bounds.height - options[:height]) * 0.33 * j
67
+ box = Prawn::Text::Box.new(get_string(i, j), options)
23
68
 
24
- text_box "Oh hai text box. " * 100, :overflow => :expand
69
+ fill_color("ffeeee")
70
+ if i == 1
71
+ # bound with a box of a particular size, regardless of how
72
+ # much text it contains
73
+ fill_and_stroke_rectangle(options[:at],
74
+ options[:width],
75
+ options[:height])
76
+ else
77
+ # bound with a box that exactly fits the printed text using
78
+ # dry_run look-ahead
79
+ box.render(:dry_run => true)
80
+ fill_and_stroke_rectangle(options[:at],
81
+ options[:width],
82
+ box.height)
83
+ end
84
+ fill_color("000000")
85
+ box.render
86
+ end
87
+ end
25
88
  end
data/lib/prawn/core.rb CHANGED
@@ -25,7 +25,7 @@ module Prawn
25
25
  # The base source directory for Prawn as installed on the system
26
26
  BASEDIR = File.expand_path(File.join(dir, '..', '..'))
27
27
 
28
- VERSION = "0.6.3"
28
+ VERSION = "0.7.1"
29
29
 
30
30
  extend self
31
31
 
@@ -73,6 +73,7 @@ require "prawn/compatibility"
73
73
  require "prawn/errors"
74
74
  require "prawn/pdf_object"
75
75
  require "prawn/object_store"
76
+ require "prawn/text"
76
77
  require "prawn/graphics"
77
78
  require "prawn/images"
78
79
  require "prawn/images/jpg"
@@ -83,3 +84,4 @@ require "prawn/reference"
83
84
  require "prawn/font"
84
85
  require "prawn/encoding"
85
86
  require "prawn/measurements"
87
+ require "prawn/repeater"
@@ -223,6 +223,15 @@ module Prawn
223
223
 
224
224
  # Temporarily adjust the @x coordinate to allow for left_padding
225
225
  #
226
+ # Example:
227
+ #
228
+ # indent 20 do
229
+ # text "20 points in"
230
+ # indent 30 do
231
+ # text "50 points in"
232
+ # end
233
+ # end
234
+ #
226
235
  def indent(left_padding, &block)
227
236
  @x += left_padding
228
237
  @width -= left_padding
@@ -43,22 +43,29 @@ module Prawn
43
43
 
44
44
  # Template methods to support ColumnBox extensions
45
45
  class BoundingBox
46
+
47
+ # an alias for absolute_left
46
48
  def left_side
47
49
  absolute_left
48
50
  end
49
51
 
52
+ # an alias for absolute_right
50
53
  def right_side
51
54
  absolute_right
52
55
  end
53
56
 
57
+ # starts a new page
54
58
  def move_past_bottom
55
59
  @parent.start_new_page
56
60
  end
57
61
  end
58
62
 
63
+ # Implements the necessary functionality to allow Document#column_box to
64
+ # work.
65
+ #
59
66
  class ColumnBox < BoundingBox
60
67
 
61
- def initialize(parent, point, options={})
68
+ def initialize(parent, point, options={}) #:nodoc:
62
69
  super
63
70
  @columns = options[:columns] || 3
64
71
  @spacer = options[:spacer] || @parent.font_size
@@ -72,6 +79,8 @@ module Prawn
72
79
  super / @columns - @spacer
73
80
  end
74
81
 
82
+ # Column width including the spacer.
83
+ #
75
84
  def width_of_column
76
85
  width + @spacer
77
86
  end
@@ -89,7 +98,9 @@ module Prawn
89
98
  absolute_right - (width_of_column * columns_from_right)
90
99
  end
91
100
 
92
- def move_past_bottom #:nodoc:
101
+ # Moves to the next column or starts a new page if currently positioned at
102
+ # the rightmost column.
103
+ def move_past_bottom
93
104
  @current_column = (@current_column + 1) % @columns
94
105
  @parent.y = @y
95
106
  if 0 == @current_column
@@ -79,6 +79,8 @@ module Prawn
79
79
  page_resources[:XObject] ||= {}
80
80
  end
81
81
 
82
+ # The ExtGState dictionary for the current page
83
+ #
82
84
  def page_ext_gstates
83
85
  page_resources[:ExtGState] ||= {}
84
86
  end
@@ -91,6 +93,12 @@ module Prawn
91
93
  @store.root.data[:Names] ||= ref!(:Type => :Names)
92
94
  end
93
95
 
96
+ # Returns true if the Names dictionary is in use for this document.
97
+ #
98
+ def names?
99
+ @store.root.data[:Names]
100
+ end
101
+
94
102
  # Defines a block to be called just before the document is rendered.
95
103
  #
96
104
  def before_render(&block)
@@ -103,13 +111,22 @@ module Prawn
103
111
  @page_content = jump_to.data[:Contents].identifier
104
112
  end
105
113
 
114
+ # Defines a block to be called just before a new page is started.
115
+ #
116
+ def on_page_create(&block)
117
+ if block_given?
118
+ @on_page_create_callback = block
119
+ else
120
+ @on_page_create_callback = nil
121
+ end
122
+ end
123
+
106
124
  private
107
125
 
108
126
  def finalize_all_page_contents
109
- page_count.times do |i|
127
+ (1..page_count).each do |i|
110
128
  go_to_page i
111
- @header.draw if defined?(@header) and @header
112
- @footer.draw if defined?(@footer) and @footer
129
+ repeaters.each { |r| r.run(i) }
113
130
  add_content "Q"
114
131
  page_content.compress_stream if compression_enabled?
115
132
  page_content.data[:Length] = page_content.stream.size
@@ -138,6 +155,7 @@ module Prawn
138
155
  # Write out the PDF Body, as per spec 3.4.2
139
156
  #
140
157
  def render_body(output)
158
+ @store.compact if @optimize_objects
141
159
  @store.each do |ref|
142
160
  ref.offset = output.size
143
161
  output << ref.object
@@ -17,6 +17,7 @@ module Prawn
17
17
  # prevent any of its data from being rendered. You must reset the
18
18
  # y-position yourself if you have performed any drawing operations that
19
19
  # modify it.
20
+ #
20
21
  def rollback
21
22
  raise RollbackTransaction
22
23
  end
@@ -28,6 +29,7 @@ module Prawn
28
29
  # yourself).
29
30
  #
30
31
  # Returns true on success, or false if the transaction was rolled back.
32
+ #
31
33
  def transaction
32
34
  snap = take_snapshot
33
35
  yield
@@ -45,7 +47,8 @@ module Prawn
45
47
  {:page_content => Marshal.load(Marshal.dump(page_content)),
46
48
  :current_page => Marshal.load(Marshal.dump(current_page)),
47
49
  :page_kids => @store.pages.data[:Kids].map{|kid| kid.identifier},
48
- :dests => Marshal.load(Marshal.dump(names.data[:Dests]))}
50
+ :dests => names? &&
51
+ Marshal.load(Marshal.dump(names.data[:Dests]))}
49
52
  end
50
53
 
51
54
  # Rolls the page state back to the state of the given snapshot.
@@ -64,7 +67,9 @@ module Prawn
64
67
  @store.pages.data[:Kids] = shot[:page_kids].map{|id| @store[id]}
65
68
  @store.pages.data[:Count] = shot[:page_kids].size
66
69
 
67
- names.data[:Dests] = shot[:dests]
70
+ if shot[:dests]
71
+ names.data[:Dests] = shot[:dests]
72
+ end
68
73
  end
69
74
 
70
75
  end
@@ -27,8 +27,8 @@ module Prawn
27
27
  def span(width, options={})
28
28
  Prawn.verify_options [:position], options
29
29
  original_position = self.y
30
-
31
- # FIXME: How many effing times do I want to write this same code?
30
+
31
+ # FIXME: Any way to move this upstream?
32
32
  left_boundary = case(options[:position] || :left)
33
33
  when :left
34
34
  margin_box.absolute_left
@@ -52,4 +52,4 @@ module Prawn
52
52
  end
53
53
  end
54
54
  end
55
- end
55
+ end
@@ -12,7 +12,6 @@ require "prawn/document/bounding_box"
12
12
  require "prawn/document/column_box"
13
13
  require "prawn/document/internals"
14
14
  require "prawn/document/span"
15
- require "prawn/document/text"
16
15
  require "prawn/document/annotations"
17
16
  require "prawn/document/destinations"
18
17
  require "prawn/document/snapshot"
@@ -60,6 +59,7 @@ module Prawn
60
59
  include Annotations
61
60
  include Destinations
62
61
  include Snapshot
62
+ include Prawn::Text
63
63
  include Prawn::Graphics
64
64
  include Prawn::Images
65
65
  include Prawn::Stamp
@@ -69,11 +69,31 @@ module Prawn
69
69
  attr_writer :font_size
70
70
 
71
71
 
72
+ # Any module added to this array will be included into instances of
73
+ # Prawn::Document at the per-object level. These will also be inherited by
74
+ # any subclasses.
75
+ #
76
+ # Example:
77
+ #
78
+ # module MyFancyModule
79
+ #
80
+ # def party!
81
+ # text "It's a big party!"
82
+ # end
83
+ #
84
+ # end
85
+ #
86
+ # Prawn::Document.extensions << MyFancyModule
87
+ #
88
+ # Prawn::Document.generate("foo.pdf") do
89
+ # party!
90
+ # end
91
+ #
72
92
  def self.extensions
73
93
  @extensions ||= []
74
94
  end
75
95
 
76
- def self.inherited(base)
96
+ def self.inherited(base) #:nodoc:
77
97
  extensions.each { |e| base.extensions << e }
78
98
  end
79
99
 
@@ -121,6 +141,7 @@ module Prawn
121
141
  # <tt>:bottom_margin</tt>:: Sets the bottom margin in points [0.5 inch]
122
142
  # <tt>:skip_page_creation</tt>:: Creates a document without starting the first page [false]
123
143
  # <tt>:compress</tt>:: Compresses content streams before rendering them [false]
144
+ # <tt>:optimize_objects</tt>:: Reduce number of PDF objects in output, at expense of render time [false]
124
145
  # <tt>:background</tt>:: An image path to be used as background on all pages [nil]
125
146
  # <tt>:info</tt>:: Generic hash allowing for custom metadata properties [nil]
126
147
  # <tt>:text_options</tt>:: A set of default options to be handed to text(). Be careful with this.
@@ -157,7 +178,8 @@ module Prawn
157
178
  def initialize(options={},&block)
158
179
  Prawn.verify_options [:page_size, :page_layout, :margin, :left_margin,
159
180
  :right_margin, :top_margin, :bottom_margin, :skip_page_creation,
160
- :compress, :skip_encoding, :text_options, :background, :info], options
181
+ :compress, :skip_encoding, :text_options, :background, :info,
182
+ :optimize_objects], options
161
183
 
162
184
  self.class.extensions.reverse_each { |e| extend e }
163
185
 
@@ -175,10 +197,12 @@ module Prawn
175
197
  @store = ObjectStore.new(options[:info])
176
198
  @trailer = {}
177
199
  @before_render_callbacks = []
200
+ @on_page_create_callback = nil
178
201
 
179
202
  @page_size = options[:page_size] || "LETTER"
180
203
  @page_layout = options[:page_layout] || :portrait
181
204
  @compress = options[:compress] || false
205
+ @optimize_objects = options.fetch(:optimize_objects, false)
182
206
  @skip_encoding = options[:skip_encoding]
183
207
  @background = options[:background]
184
208
  @font_size = 12
@@ -199,6 +223,7 @@ module Prawn
199
223
  generate_margin_box
200
224
 
201
225
  @bounding_box = @margin_box
226
+ @page_number = 0
202
227
 
203
228
  start_new_page unless options[:skip_page_creation]
204
229
 
@@ -218,6 +243,7 @@ module Prawn
218
243
  # pdf.start_new_page(:margin => 100)
219
244
  #
220
245
  def start_new_page(options = {})
246
+
221
247
  @page_size = options[:size] if options[:size]
222
248
  @page_layout = options[:layout] if options[:layout]
223
249
 
@@ -230,15 +256,20 @@ module Prawn
230
256
  end
231
257
 
232
258
  build_new_page_content
233
-
234
- @store.pages.data[:Kids] << current_page
259
+
260
+ @store.pages.data[:Kids].insert(@page_number, current_page)
235
261
  @store.pages.data[:Count] += 1
236
-
262
+ @page_number += 1
263
+
237
264
  add_content "q"
238
-
265
+
239
266
  @y = @bounding_box.absolute_top
240
267
 
241
268
  image(@background, :at => [0,@y]) if @background
269
+
270
+ float do
271
+ @on_page_create_callback.call(self) if @on_page_create_callback
272
+ end
242
273
  end
243
274
 
244
275
  # Returns the number of pages in the document
@@ -252,6 +283,26 @@ module Prawn
252
283
  @store.pages.data[:Count]
253
284
  end
254
285
 
286
+ # Returns the 1-based page number of the current page. Returns 0 if the
287
+ # document has no pages.
288
+ #
289
+ def page_number
290
+ @page_number
291
+ end
292
+
293
+ # Re-opens the page with the given (1-based) page number so that you can
294
+ # draw on it. Does not restore page state such as margins, page orientation,
295
+ # or paper size, so you'll have to handle that yourself.
296
+ #
297
+ # See Prawn::Document#number_pages for a sample usage of this capability.
298
+ #
299
+ def go_to_page(k)
300
+ @page_number = k
301
+ jump_to = @store.pages.data[:Kids][k-1]
302
+ @current_page = jump_to.identifier
303
+ @page_content = jump_to.data[:Contents].identifier
304
+ end
305
+
255
306
  def y=(new_y)
256
307
  @y = new_y
257
308
  bounds.update_height
@@ -271,15 +322,22 @@ module Prawn
271
322
  self.y = new_y + bounds.absolute_bottom
272
323
  end
273
324
 
274
- # Renders the PDF document to string, useful for example in a Rails
275
- # application where you want to stream out the PDF to a web browser:
276
- #
277
- # def show
278
- # pdf = Prawn::Document.new do
279
- # text "Putting PDF generation code in a controller is _BAD_"
280
- # end
281
- # send(pdf.render, :filename => 'silly.pdf', :type => 'application/pdf', :disposition => 'inline)
282
- # end
325
+ # Executes a block and then restores the original y position
326
+ #
327
+ # pdf.text "A"
328
+ #
329
+ # pdf.float do
330
+ # pdf.move_down 100
331
+ # pdf.text "C"
332
+ # end
333
+ #
334
+ # pdf.text "B"
335
+ #
336
+ def float
337
+ mask(:y) { yield }
338
+ end
339
+
340
+ # Renders the PDF document to string
283
341
  #
284
342
  def render
285
343
  output = StringIO.new
@@ -426,7 +484,7 @@ module Prawn
426
484
  # Raised if group() is called with a block that is too big to be
427
485
  # rendered in the current context.
428
486
  #
429
- CannotGroup = Class.new(StandardError)
487
+ CannotGroup = Class.new(StandardError) #FIXME: should be in prawn/errors.rb
430
488
 
431
489
  # Attempts to group the given block vertically within the current context.
432
490
  # First attempts to render it in the current position on the current page.
@@ -470,9 +528,10 @@ module Prawn
470
528
  # text "-- Hai again"
471
529
  # number_pages "<page> in a total of <total>", [bounds.right - 50, 0]
472
530
  # end
531
+ #
473
532
  def number_pages(string, position)
474
533
  page_count.times do |i|
475
- go_to_page(i)
534
+ go_to_page(i+1)
476
535
  str = string.gsub("<page>","#{i+1}").gsub("<total>","#{page_count}")
477
536
  text str, :at => position
478
537
  end
@@ -488,7 +547,7 @@ module Prawn
488
547
  private
489
548
 
490
549
  # See Prawn::Document::Internals for low-level PDF functions
491
-
550
+ #
492
551
  def build_new_page_content
493
552
  generate_margin_box
494
553
  @page_content = ref(:Length => 0)