pdf-wrapper 0.0.7 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|