prawn-core 0.6.3 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/examples/general/context_sensitive_headers.rb +37 -0
- data/examples/general/float.rb +11 -0
- data/examples/general/repeaters.rb +43 -0
- data/examples/m17n/chinese_text_wrapping.rb +1 -3
- data/examples/text/font_calculations.rb +6 -6
- data/examples/text/text_box.rb +80 -17
- data/lib/prawn/core.rb +3 -1
- data/lib/prawn/document/bounding_box.rb +9 -0
- data/lib/prawn/document/column_box.rb +13 -2
- data/lib/prawn/document/internals.rb +21 -3
- data/lib/prawn/document/snapshot.rb +7 -2
- data/lib/prawn/document/span.rb +3 -3
- data/lib/prawn/document.rb +78 -19
- data/lib/prawn/font/afm.rb +10 -7
- data/lib/prawn/font/ttf.rb +6 -4
- data/lib/prawn/font.rb +34 -24
- data/lib/prawn/graphics/cap_style.rb +5 -2
- data/lib/prawn/graphics/color.rb +117 -57
- data/lib/prawn/graphics/dash.rb +4 -2
- data/lib/prawn/graphics/join_style.rb +6 -3
- data/lib/prawn/graphics/transparency.rb +65 -18
- data/lib/prawn/images/jpg.rb +1 -1
- data/lib/prawn/images/png.rb +1 -1
- data/lib/prawn/object_store.rb +30 -1
- data/lib/prawn/reference.rb +25 -3
- data/lib/prawn/repeater.rb +117 -0
- data/lib/prawn/stamp.rb +102 -40
- data/lib/prawn/text/box.rb +344 -0
- data/lib/prawn/text.rb +255 -0
- data/spec/document_spec.rb +125 -4
- data/spec/object_store_spec.rb +33 -0
- data/spec/repeater_spec.rb +79 -0
- data/spec/stamp_spec.rb +8 -0
- data/spec/text_box_spec.rb +282 -69
- data/spec/text_spec.rb +49 -29
- data/spec/transparency_spec.rb +14 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +2 -2
- metadata +158 -155
- data/examples/general/measurement_units.pdf +0 -4667
- data/lib/prawn/document/text/box.rb +0 -90
- data/lib/prawn/document/text/wrapping.rb +0 -62
- data/lib/prawn/document/text.rb +0 -184
data/Rakefile
CHANGED
@@ -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,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
|
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
|
68
|
-
stroke_line [0, bl
|
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
|
72
|
-
stroke_line [0, bl
|
73
|
-
[bounds.width,bl
|
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
|
77
|
+
[bounds.width, bl - font.descender - font.line_gap]
|
78
78
|
|
79
79
|
stroke_color "000000"
|
80
80
|
fill_color "000000"
|
data/examples/text/text_box.rb
CHANGED
@@ -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
|
-
|
4
|
+
require 'examples/example_helper'
|
11
5
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
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.
|
127
|
+
(1..page_count).each do |i|
|
110
128
|
go_to_page i
|
111
|
-
|
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 =>
|
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
|
-
|
70
|
+
if shot[:dests]
|
71
|
+
names.data[:Dests] = shot[:dests]
|
72
|
+
end
|
68
73
|
end
|
69
74
|
|
70
75
|
end
|
data/lib/prawn/document/span.rb
CHANGED
@@ -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:
|
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
|
data/lib/prawn/document.rb
CHANGED
@@ -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
|
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]
|
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
|
-
#
|
275
|
-
#
|
276
|
-
#
|
277
|
-
#
|
278
|
-
#
|
279
|
-
#
|
280
|
-
#
|
281
|
-
#
|
282
|
-
#
|
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)
|