pdf-wrapper 0.0.7 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +11 -0
- data/Rakefile +4 -4
- data/examples/cell.rb +1 -1
- data/examples/image.rb +3 -3
- data/examples/markup.rb +12 -0
- data/examples/repeating.rb +1 -1
- data/examples/scaled.rb +38 -0
- data/examples/scaled_cells.rb +30 -0
- data/examples/scaled_image.rb +14 -0
- data/examples/shapes.rb +1 -1
- data/examples/table.rb +25 -4
- data/examples/translate.rb +21 -0
- data/examples/utf8-long.rb +1 -2
- data/examples/utf8.rb +1 -2
- data/lib/pdf/core.rb +23 -0
- data/lib/pdf/wrapper.rb +136 -760
- data/lib/pdf/wrapper/graphics.rb +116 -0
- data/lib/pdf/wrapper/images.rb +206 -0
- data/lib/pdf/wrapper/loading.rb +52 -0
- data/lib/pdf/wrapper/table.rb +473 -0
- data/lib/pdf/wrapper/text.rb +337 -0
- data/specs/data/windmill.jpg +0 -0
- data/specs/{shapes_spec.rb → graphics_spec.rb} +3 -3
- data/specs/spec_helper.rb +6 -1
- data/specs/tables_spec.rb +111 -0
- data/specs/text_spec.rb +63 -2
- data/specs/wrapper_spec.rb +145 -72
- metadata +20 -9
- data/examples/padded_image.rb +0 -12
- data/examples/template.rb +0 -13
@@ -0,0 +1,337 @@
|
|
1
|
+
module PDF
|
2
|
+
class Wrapper
|
3
|
+
|
4
|
+
# change the default font size
|
5
|
+
def font_size(size)
|
6
|
+
@default_font_size = size.to_i unless size.nil?
|
7
|
+
end
|
8
|
+
alias font_size= font_size
|
9
|
+
|
10
|
+
# change the default font to write with
|
11
|
+
def font(fontname, style = nil, weight = nil)
|
12
|
+
@default_font = fontname
|
13
|
+
@default_font_style = style unless style.nil?
|
14
|
+
@default_font_weight = weight unless weight.nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
# add text to the page, bounded by a box with dimensions HxW, with it's top left corner
|
18
|
+
# at x,y. Any text that doesn't fit it the box will be silently dropped.
|
19
|
+
#
|
20
|
+
# In addition to the standard text style options (see the documentation for text()), cell() supports
|
21
|
+
# the following options:
|
22
|
+
#
|
23
|
+
# <tt>:border</tt>:: Which sides of the cell should have a border? A string with any combination the letters tblr (top, bottom, left, right). Nil for no border, defaults to all sides.
|
24
|
+
# <tt>:border_width</tt>:: How wide should the border be?
|
25
|
+
# <tt>:border_color</tt>:: What color should the border be?
|
26
|
+
# <tt>:fill_color</tt>:: A background color for the cell. Defaults to none.
|
27
|
+
# <tt>:radius</tt>:: Give the border around the cell rounded corners. Implies :border => "tblr"
|
28
|
+
def cell(str, x, y, w, h, opts={})
|
29
|
+
# TODO: add a wrap option so wrapping can be disabled
|
30
|
+
# TODO: add an option for vertical alignment
|
31
|
+
|
32
|
+
options = default_text_options
|
33
|
+
options.merge!({:border => "tblr", :border_width => @default_line_width, :border_color => :black, :fill_color => nil, :padding => device_to_user_dist(3,0).first, :radius => nil})
|
34
|
+
options.merge!(opts)
|
35
|
+
options.assert_valid_keys(default_text_options.keys + [:width, :border, :border_width, :border_color, :fill_color, :padding, :radius])
|
36
|
+
|
37
|
+
# apply padding
|
38
|
+
textw = w - (options[:padding] * 2)
|
39
|
+
texth = h - (options[:padding] * 2)
|
40
|
+
|
41
|
+
# if the user wants a rounded rectangle, we'll draw the border with a rectangle instead
|
42
|
+
# of 4 lines
|
43
|
+
options[:border] = nil if options[:radius]
|
44
|
+
|
45
|
+
# normalise the border
|
46
|
+
options[:border] = "" unless options[:border]
|
47
|
+
options[:border].downcase!
|
48
|
+
|
49
|
+
save_coords do
|
50
|
+
translate(x, y) do
|
51
|
+
# draw a border around the cell
|
52
|
+
if options[:radius]
|
53
|
+
rectangle(0,0,w,h, :radius => options[:radius], :color => options[:border_color], :fill_color => options[:fill_color], :line_width => options[:border_width])
|
54
|
+
else
|
55
|
+
rectangle(0,0,w,h, :color => options[:fill_color], :fill_color => options[:fill_color]) if options[:fill_color]
|
56
|
+
line(0,0,w,0, :color => options[:border_color], :line_width => options[:border_width]) if options[:border].include?("t")
|
57
|
+
line(0,h,w,h, :color => options[:border_color], :line_width => options[:border_width]) if options[:border].include?("b")
|
58
|
+
line(0,0,0,h, :color => options[:border_color], :line_width => options[:border_width]) if options[:border].include?("l")
|
59
|
+
line(w,0,w,h, :color => options[:border_color], :line_width => options[:border_width]) if options[:border].include?("r")
|
60
|
+
end
|
61
|
+
|
62
|
+
layout = build_pango_layout(str.to_s, textw, options)
|
63
|
+
|
64
|
+
color(options[:color]) if options[:color]
|
65
|
+
|
66
|
+
# draw the context on our cairo layout
|
67
|
+
render_layout(layout, options[:padding], options[:padding], texth, :auto_new_page => false)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Write text to the page
|
74
|
+
#
|
75
|
+
# By default the text will be rendered using all the space within the margins and using
|
76
|
+
# the default font styling set by default_font(), default_font_size, etc
|
77
|
+
#
|
78
|
+
# There is no way to place a bottom bound (or height) onto the text. Text will wrap as
|
79
|
+
# necessary and take all the room it needs. For finer grained control of text boxes, see the
|
80
|
+
# cell method.
|
81
|
+
#
|
82
|
+
# To override all these defaults, use the options hash
|
83
|
+
#
|
84
|
+
# Positioning Options:
|
85
|
+
#
|
86
|
+
# <tt>:left</tt>:: The x co-ordinate of the left-hand side of the text.
|
87
|
+
# <tt>:top</tt>:: The y co-ordinate of the top of the text.
|
88
|
+
# <tt>:width</tt>:: The width of the text to wrap at
|
89
|
+
#
|
90
|
+
# Text Style Options:
|
91
|
+
#
|
92
|
+
# <tt>:font</tt>:: The font family to use as a string
|
93
|
+
# <tt>:font_size</tt>:: The size of the font in points
|
94
|
+
# <tt>:alignment</tt>:: Align the text along the left, right or centre. Use :left, :right, :center
|
95
|
+
# <tt>:wrap</tt>:: The wrapping technique to use if required. Use :word, :char or :wordchar. Default is :wordchar
|
96
|
+
# <tt>:justify</tt>:: Justify the text so it exapnds to fill the entire width of each line. Note that this only works in pango >= 1.17
|
97
|
+
# <tt>:spacing</tt>:: Space between lines in PDF points
|
98
|
+
# <tt>:markup</tt>:: Interpret the text as a markup language. Default is nil (none).
|
99
|
+
#
|
100
|
+
# = Markup
|
101
|
+
#
|
102
|
+
# If the markup option is specified, the text can be modified in various ways. At this stage
|
103
|
+
# the only markup syntax implemented is :pango.
|
104
|
+
#
|
105
|
+
# == Pango Markup
|
106
|
+
#
|
107
|
+
# Full details on the Pango markup language are avaialble at http://ruby-gnome2.sourceforge.jp/hiki.cgi?pango-markup
|
108
|
+
#
|
109
|
+
# The format is vaguely XML-like.
|
110
|
+
#
|
111
|
+
# Bold: "Some of this text is <b>bold</b>."
|
112
|
+
# Italics: "Some of this text is in <b>italics</b>."
|
113
|
+
# Strikethrough: "My name is <s>Bob</s>James."
|
114
|
+
# Monospace Font: "Code:\n<tt>puts 1</tt>."
|
115
|
+
#
|
116
|
+
# For more advanced control, use span tags
|
117
|
+
#
|
118
|
+
# Big and Bold: Some of this text is <span weight="bold" font_desc="20">bold</span>.
|
119
|
+
# Stretched: Some of this text is <span stretch="extraexpanded">funny looking</span>.
|
120
|
+
def text(str, opts={})
|
121
|
+
# TODO: add converters from various markup languages to pango markup. (markdown, textile, etc)
|
122
|
+
# TODO: add a wrap option so wrapping can be disabled
|
123
|
+
#
|
124
|
+
# the non pango way to add text to the cairo context, not particularly useful for
|
125
|
+
# PDF generation as it doesn't support wrapping text or other advanced layout features
|
126
|
+
# and I really don't feel like re-implementing all that
|
127
|
+
# @context.show_text(str)
|
128
|
+
|
129
|
+
# the "pango way"
|
130
|
+
x, y = current_point
|
131
|
+
options = default_text_options.merge!({:left => x, :top => y})
|
132
|
+
options.merge!(opts)
|
133
|
+
options.assert_valid_keys(default_text_options.keys + default_positioning_options.keys)
|
134
|
+
|
135
|
+
# if the user hasn't specified a width, make the text wrap on the right margin
|
136
|
+
options[:width] = absolute_right_margin - options[:left] if options[:width].nil?
|
137
|
+
|
138
|
+
layout = build_pango_layout(str.to_s, options[:width], options)
|
139
|
+
|
140
|
+
color(options[:color]) if options[:color]
|
141
|
+
|
142
|
+
# draw the context on our cairo layout
|
143
|
+
y = render_layout(layout, options[:left], options[:top], points_to_bottom_margin(options[:top]), :auto_new_page => true)
|
144
|
+
|
145
|
+
move_to(options[:left], y + device_y_to_user_y(5))
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns the amount of vertical space needed to display the supplied text at the requested width
|
149
|
+
# opts is an options hash that specifies various attributes of the text. See the text function for more information.
|
150
|
+
def text_height(str, width, opts = {})
|
151
|
+
options = default_text_options.merge(opts)
|
152
|
+
options.assert_valid_keys(default_text_options.keys)
|
153
|
+
options[:width] = width || body_width
|
154
|
+
|
155
|
+
layout = build_pango_layout(str.to_s, options[:width], options)
|
156
|
+
width, height = layout.size
|
157
|
+
|
158
|
+
return height / Pango::SCALE
|
159
|
+
end
|
160
|
+
|
161
|
+
# Returns the amount of horizontal space needed to display the supplied text with the requested options
|
162
|
+
# opts is an options hash that specifies various attributes of the text. See the text function for more information.
|
163
|
+
# The text is assumed to not wrap.
|
164
|
+
def text_width(str, opts = {})
|
165
|
+
options = default_text_options.merge(opts)
|
166
|
+
options.assert_valid_keys(default_text_options.keys)
|
167
|
+
|
168
|
+
layout = build_pango_layout(str.to_s, -1, options)
|
169
|
+
width, height = layout.size
|
170
|
+
|
171
|
+
return width / Pango::SCALE
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
# takes a string and a range of options and creates a pango layout for us. Pango
|
177
|
+
# does all the hard work of calculating text layout, wrapping, fonts, sizes,
|
178
|
+
# direction and more. Thank $diety.
|
179
|
+
#
|
180
|
+
# The string should be encoded using utf-8. If you get unexpected characters in the
|
181
|
+
# rendered output, check the string encoding. Under Ruby 1.9 compatible VMs, any
|
182
|
+
# non utf-8 strings will be automatically converted if possible.
|
183
|
+
#
|
184
|
+
# The layout will be constrained to the requested width, but has no maximum height. It
|
185
|
+
# is up to some other part of the code to decide how much of the layout should actually
|
186
|
+
# be rendered to the document, when page breaks should be inserted, etc. To specify no
|
187
|
+
# wrapping, set width to nil. This will result in a single line layout that is as wide
|
188
|
+
# as it needs to be to fit the entire string.
|
189
|
+
#
|
190
|
+
# options:
|
191
|
+
# <tt>:markup</tt>:: The markup language of the string. See Wrapper#text for more information
|
192
|
+
# <tt>:spacing</tt>:: The spacing between lines. See Wrapper#text for more information
|
193
|
+
# <tt>:alignment</tt>:: The alignment of the text. See Wrapper#text for more information
|
194
|
+
# <tt>:justify</tt>:: Should spacing between words be tweaked so each edge of the line touches
|
195
|
+
# the edge of the layout. See Wrapper#text for more information
|
196
|
+
# <tt>:font</tt>:: The font to use. See Wrapper#text for more information
|
197
|
+
# <tt>:font_size</tt>:: The font size to use. See Wrapper#text for more information
|
198
|
+
# <tt>:wrap</tt>:: The wrap technique to use. See Wrapper#text for more information
|
199
|
+
def build_pango_layout(str, w, opts = {})
|
200
|
+
options = default_text_options.merge!(opts)
|
201
|
+
|
202
|
+
# if the user hasn't specified a width, make the layout as wide as the page body
|
203
|
+
w = body_width if w.nil?
|
204
|
+
|
205
|
+
# even though this is a private function, raise this error to force calling functions
|
206
|
+
# to decide how they want to handle converting non-strings into strings for rendering
|
207
|
+
raise ArgumentError, 'build_pango_layout must be passed a string' unless str.kind_of?(String)
|
208
|
+
|
209
|
+
# if we're running under a M17n aware VM, ensure the string provided is UTF-8 or can be
|
210
|
+
# converted to UTF-8
|
211
|
+
if RUBY_VERSION >= "1.9"
|
212
|
+
begin
|
213
|
+
str = str.encode("UTF-8")
|
214
|
+
rescue
|
215
|
+
raise ArgumentError, 'Strings must be supplied with a UTF-8 encoding, or an encoding that can be converted to UTF-8'
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# The pango way:
|
220
|
+
load_libpango
|
221
|
+
|
222
|
+
# create a new Pango layout that our text will be added to
|
223
|
+
layout = @context.create_pango_layout
|
224
|
+
if options[:markup] == :pango
|
225
|
+
layout.markup = str.to_s
|
226
|
+
else
|
227
|
+
layout.text = str.to_s
|
228
|
+
end
|
229
|
+
if w.nil? || w < 0
|
230
|
+
layout.width = -1
|
231
|
+
else
|
232
|
+
# width is specified in user points
|
233
|
+
layout.width = w * Pango::SCALE
|
234
|
+
end
|
235
|
+
# spacing is specified in user points
|
236
|
+
layout.spacing = device_y_to_user_y(options[:spacing] * Pango::SCALE)
|
237
|
+
|
238
|
+
# set the alignment of the text in the layout
|
239
|
+
if options[:alignment].eql?(:left)
|
240
|
+
layout.alignment = Pango::Layout::ALIGN_LEFT
|
241
|
+
elsif options[:alignment].eql?(:right)
|
242
|
+
layout.alignment = Pango::Layout::ALIGN_RIGHT
|
243
|
+
elsif options[:alignment].eql?(:center) || options[:alignment].eql?(:centre)
|
244
|
+
layout.alignment = Pango::Layout::ALIGN_CENTER
|
245
|
+
else
|
246
|
+
raise ArgumentError, "Invalid alignment requested"
|
247
|
+
end
|
248
|
+
|
249
|
+
# set the wrapping technique text of the layout
|
250
|
+
if options[:wrap].eql?(:word)
|
251
|
+
layout.wrap = Pango::Layout::WRAP_WORD
|
252
|
+
elsif options[:wrap].eql?(:char)
|
253
|
+
layout.wrap = Pango::Layout::WRAP_CHAR
|
254
|
+
elsif options[:wrap].eql?(:wordchar)
|
255
|
+
layout.wrap = Pango::Layout::WRAP_WORD_CHAR
|
256
|
+
else
|
257
|
+
raise ArgumentError, "Invalid wrap technique requested"
|
258
|
+
end
|
259
|
+
|
260
|
+
# justify the text if need be - only works in pango >= 1.17
|
261
|
+
layout.justify = true if options[:justify]
|
262
|
+
|
263
|
+
# setup the font that will be used to render the text
|
264
|
+
fdesc = Pango::FontDescription.new(options[:font])
|
265
|
+
# font size should be specified in device points for simplicity's sake.
|
266
|
+
fdesc.size = device_y_to_user_y(options[:font_size] * Pango::SCALE)
|
267
|
+
layout.font_description = fdesc
|
268
|
+
@context.update_pango_layout(layout)
|
269
|
+
|
270
|
+
return layout
|
271
|
+
end
|
272
|
+
|
273
|
+
def default_text_options
|
274
|
+
{ :font => @default_font,
|
275
|
+
:font_size => @default_font_size,
|
276
|
+
:alignment => :left,
|
277
|
+
:wrap => :wordchar,
|
278
|
+
:justify => false,
|
279
|
+
:spacing => 0,
|
280
|
+
:color => nil,
|
281
|
+
:markup => nil
|
282
|
+
}
|
283
|
+
end
|
284
|
+
|
285
|
+
# renders a pango layout onto our main context
|
286
|
+
# based on a function of the same name found in the text2.rb sample file
|
287
|
+
# distributed with rcairo - it's still black magic to me and has a few edge
|
288
|
+
# cases where it doesn't work too well. Needs to be improved.
|
289
|
+
def render_layout(layout, x, y, h, opts = {})
|
290
|
+
# we can't use context.show_pango_layout, as that won't start
|
291
|
+
# a new page if the layout hits the bottom margin. Instead,
|
292
|
+
# we iterate over each line of text in the layout and add it to
|
293
|
+
# the canvas, page breaking as necessary
|
294
|
+
options = {:auto_new_page => true }
|
295
|
+
options.merge!(opts)
|
296
|
+
|
297
|
+
offset = 0
|
298
|
+
baseline = 0
|
299
|
+
|
300
|
+
iter = layout.iter
|
301
|
+
loop do
|
302
|
+
line = iter.line
|
303
|
+
ink_rect, logical_rect = iter.line_extents
|
304
|
+
|
305
|
+
# calculate the relative starting co-ords of this line
|
306
|
+
baseline = iter.baseline / Pango::SCALE
|
307
|
+
linex = logical_rect.x / Pango::SCALE
|
308
|
+
|
309
|
+
if baseline - offset >= h
|
310
|
+
# our text is using the maximum amount of vertical space we want it to
|
311
|
+
if options[:auto_new_page]
|
312
|
+
# create a new page and we can continue adding text
|
313
|
+
offset = baseline
|
314
|
+
start_new_page
|
315
|
+
else
|
316
|
+
# the user doesn't want us to continue on the next page, so
|
317
|
+
# stop adding lines to the canvas
|
318
|
+
break
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# move to the start of this line
|
323
|
+
@context.move_to(x + linex, y + baseline - offset)
|
324
|
+
|
325
|
+
# draw the line on the canvas
|
326
|
+
@context.show_pango_layout_line(line)
|
327
|
+
|
328
|
+
break unless iter.next_line!
|
329
|
+
end
|
330
|
+
|
331
|
+
# return the y co-ord we finished on
|
332
|
+
return device_y_to_user_y(y + baseline - offset)
|
333
|
+
end
|
334
|
+
|
335
|
+
|
336
|
+
end
|
337
|
+
end
|
Binary file
|
@@ -101,7 +101,7 @@ context "The PDF::Wrapper class" do
|
|
101
101
|
w = h = 200
|
102
102
|
r = 5
|
103
103
|
pdf = PDF::Wrapper.new
|
104
|
-
pdf.
|
104
|
+
pdf.rectangle(x,y,w,h,:radius => r)
|
105
105
|
|
106
106
|
receiver = PDF::Reader::RegisterReceiver.new
|
107
107
|
reader = PDF::Reader.string(pdf.render, receiver)
|
@@ -118,7 +118,7 @@ context "The PDF::Wrapper class" do
|
|
118
118
|
r = 5
|
119
119
|
w = 5
|
120
120
|
pdf = PDF::Wrapper.new
|
121
|
-
pdf.rounded_rectangle(x,y,w,h,r, :line_width => w)
|
121
|
+
pdf.rounded_rectangle(x,y,w,h, :radius => r, :line_width => w)
|
122
122
|
|
123
123
|
receiver = PDF::Reader::RegisterReceiver.new
|
124
124
|
reader = PDF::Reader.string(pdf.render, receiver)
|
@@ -134,7 +134,7 @@ context "The PDF::Wrapper class" do
|
|
134
134
|
w = h = 200
|
135
135
|
r = 5
|
136
136
|
pdf = PDF::Wrapper.new
|
137
|
-
pdf.rounded_rectangle(x,y,w,h,r, :fill_color => :red)
|
137
|
+
pdf.rounded_rectangle(x,y,w,h, :radius => r, :fill_color => :red)
|
138
138
|
|
139
139
|
receiver = PDF::Reader::RegisterReceiver.new
|
140
140
|
reader = PDF::Reader.string(pdf.render, receiver)
|
data/specs/spec_helper.rb
CHANGED
@@ -25,6 +25,11 @@ class PDF::Wrapper
|
|
25
25
|
public :load_libpixbuf
|
26
26
|
public :load_libpango
|
27
27
|
public :load_libpoppler
|
28
|
+
public :user_x_to_device_x
|
29
|
+
public :user_y_to_device_y
|
30
|
+
public :user_to_device_dist
|
31
|
+
public :device_x_to_user_x
|
32
|
+
public :device_y_to_user_y
|
28
33
|
public :validate_color
|
29
34
|
end
|
30
35
|
|
@@ -52,7 +57,7 @@ class PageSizeReceiver
|
|
52
57
|
|
53
58
|
# Called when page parsing ends
|
54
59
|
def begin_page(args)
|
55
|
-
pages << args["MediaBox"] || args[:MediaBox]
|
60
|
+
pages << (args["MediaBox"] || args[:MediaBox])
|
56
61
|
end
|
57
62
|
end
|
58
63
|
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
4
|
+
|
5
|
+
context "The PDF::Wrapper class" do
|
6
|
+
specify "should be able to draw a table on the canvas using an array of data" do
|
7
|
+
pdf = PDF::Wrapper.new
|
8
|
+
data = [%w{data1 data2}, %w{data3 data4}]
|
9
|
+
pdf.table(data)
|
10
|
+
|
11
|
+
receiver = PageTextReceiver.new
|
12
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
13
|
+
|
14
|
+
receiver.content.first.include?("data1").should be_true
|
15
|
+
receiver.content.first.include?("data2").should be_true
|
16
|
+
receiver.content.first.include?("data3").should be_true
|
17
|
+
receiver.content.first.include?("data4").should be_true
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "should be able to draw a table on the canvas using a PDF::Wrapper::Table object" do
|
21
|
+
pdf = PDF::Wrapper.new
|
22
|
+
table = PDF::Wrapper::Table.new do |t|
|
23
|
+
t.data = [%w{data1 data2}, %w{data3 data4}]
|
24
|
+
end
|
25
|
+
|
26
|
+
pdf.table(table)
|
27
|
+
|
28
|
+
receiver = PageTextReceiver.new
|
29
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
30
|
+
|
31
|
+
receiver.content.first.include?("data1").should be_true
|
32
|
+
receiver.content.first.include?("data2").should be_true
|
33
|
+
receiver.content.first.include?("data3").should be_true
|
34
|
+
receiver.content.first.include?("data4").should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "should be able to draw a table on the canvas with no headings" do
|
38
|
+
pdf = PDF::Wrapper.new
|
39
|
+
|
40
|
+
table = PDF::Wrapper::Table.new do |t|
|
41
|
+
t.data = (1..50).collect { [1,2] }
|
42
|
+
t.headers = ["col1", "col2"]
|
43
|
+
t.show_headers = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
pdf.table(table)
|
47
|
+
|
48
|
+
receiver = PageTextReceiver.new
|
49
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
50
|
+
|
51
|
+
receiver.content.first.include?("col1").should be_false
|
52
|
+
receiver.content.first.include?("col2").should be_false
|
53
|
+
end
|
54
|
+
|
55
|
+
specify "should be able to draw a table on the canvas with headers on the first page only" do
|
56
|
+
pdf = PDF::Wrapper.new
|
57
|
+
|
58
|
+
table = PDF::Wrapper::Table.new do |t|
|
59
|
+
t.data = (1..50).collect { [1,2] }
|
60
|
+
t.headers = ["col1", "col2"]
|
61
|
+
t.show_headers = :once
|
62
|
+
end
|
63
|
+
|
64
|
+
pdf.table(table)
|
65
|
+
|
66
|
+
receiver = PageTextReceiver.new
|
67
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
68
|
+
|
69
|
+
receiver.content[0].include?("col1").should be_true
|
70
|
+
receiver.content[0].include?("col2").should be_true
|
71
|
+
receiver.content[1].include?("col1").should be_false
|
72
|
+
receiver.content[1].include?("col2").should be_false
|
73
|
+
end
|
74
|
+
|
75
|
+
specify "should be able to draw a table on the canvas with headers on all pages" do
|
76
|
+
pdf = PDF::Wrapper.new
|
77
|
+
|
78
|
+
table = PDF::Wrapper::Table.new do |t|
|
79
|
+
t.data = (1..50).collect { [1,2] }
|
80
|
+
t.headers = ["col1", "col2"]
|
81
|
+
t.show_headers = :page
|
82
|
+
end
|
83
|
+
|
84
|
+
pdf.table(table)
|
85
|
+
|
86
|
+
receiver = PageTextReceiver.new
|
87
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
88
|
+
|
89
|
+
receiver.content[0].include?("col1").should be_true
|
90
|
+
receiver.content[0].include?("col2").should be_true
|
91
|
+
receiver.content[1].include?("col1").should be_true
|
92
|
+
receiver.content[1].include?("col2").should be_true
|
93
|
+
end
|
94
|
+
|
95
|
+
specify "should leave the cursor in the bottom left when adding a table" do
|
96
|
+
pdf = PDF::Wrapper.new
|
97
|
+
data = [%w{head1 head2},%w{data1 data2}]
|
98
|
+
pdf.table(data, :left => pdf.margin_left)
|
99
|
+
x,y = pdf.current_point
|
100
|
+
x.to_i.should eql(pdf.margin_left)
|
101
|
+
end
|
102
|
+
|
103
|
+
specify "should default to using as much available space when adding a table that isn't left aligned with the left margin" do
|
104
|
+
pdf = PDF::Wrapper.new
|
105
|
+
data = [%w{head1 head2},%w{data1 data2}]
|
106
|
+
pdf.table(data, :left => 100)
|
107
|
+
x,y = pdf.current_point
|
108
|
+
x.to_i.should eql(100)
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|