Class: PDF::Wrapper
- Inherits:
-
Object
- Object
- PDF::Wrapper
- Defined in:
- lib/pdf/wrapper.rb,
lib/pdf/wrapper/page.rb,
lib/pdf/wrapper/text.rb,
lib/pdf/wrapper/table.rb,
lib/pdf/wrapper/images.rb,
lib/pdf/wrapper/graphics.rb,
lib/pdf/wrapper/text_cell.rb,
lib/pdf/wrapper/text_image_cell.rb
Overview
Create PDF files by using the cairo and pango libraries.
Rendering to a file
require 'pdf/wrapper'
pdf = PDF::Wrapper.new("somefile.pdf", :paper => :A4)
pdf.text "Hello World"
pdf.finish
Rendering to a file (alternative)
require 'pdf/wrapper'
File.open("somefile.pdf", "w") do |output|
pdf = PDF::Wrapper.new(output, :paper => :A4)
pdf.text "Hello World"
pdf.finish
end
Rendering to a string
require 'pdf/wrapper'
output = StringIO.new
pdf = PDF::Wrapper.new(output, :paper => :A4)
pdf.text "Hello World", :font_size => 16
pdf.finish
puts output.string
Block format
Avoid the need to call finish()
require 'pdf/wrapper'
PDF::Wrapper.open("somefile.pdf", :paper => :A4)
pdf.text "Hello World", :font_size => 16
end
Changing the default font
require 'pdf/wrapper'
pdf = PDF::Wrapper.new("file.pdf", :paper => :A4)
pdf.font("Monospace")
pdf.text "Hello World", :font => "Sans Serif", :font_size => 18
pdf.text "Pretend this is a code sample"
pdf.finish
Defined Under Namespace
Classes: Page, Table, TextCell, TextImageCell
Constant Summary collapse
- PAGE_SIZES =
borrowed from PDF::Writer
{ # :value {...}: #:4A0 => [4767.87, 6740.79], :2A0 => [3370.39, 4767.87], :A0 => [2383.94, 3370.39], :A1 => [1683.78, 2383.94], :A2 => [1190.55, 1683.78], :A3 => [841.89, 1190.55], :A4 => [595.28, 841.89], :A5 => [419.53, 595.28], :A6 => [297.64, 419.53], :A7 => [209.76, 297.64], :A8 => [147.40, 209.76], :A9 => [104.88, 147.40], :A10 => [73.70, 104.88], :B0 => [2834.65, 4008.19], :B1 => [2004.09, 2834.65], :B2 => [1417.32, 2004.09], :B3 => [1000.63, 1417.32], :B4 => [708.66, 1000.63], :B5 => [498.90, 708.66], :B6 => [354.33, 498.90], :B7 => [249.45, 354.33], :B8 => [175.75, 249.45], :B9 => [124.72, 175.75], :B10 => [87.87, 124.72], :C0 => [2599.37, 3676.54], :C1 => [1836.85, 2599.37], :C2 => [1298.27, 1836.85], :C3 => [918.43, 1298.27], :C4 => [649.13, 918.43], :C5 => [459.21, 649.13], :C6 => [323.15, 459.21], :C7 => [229.61, 323.15], :C8 => [161.57, 229.61], :C9 => [113.39, 161.57], :C10 => [79.37, 113.39], :RA0 => [2437.80, 3458.27], :RA1 => [1729.13, 2437.80], :RA2 => [1218.90, 1729.13], :RA3 => [864.57, 1218.90], :RA4 => [609.45, 864.57], :SRA0 => [2551.18, 3628.35], :SRA1 => [1814.17, 2551.18], :SRA2 => [1275.59, 1814.17], :SRA3 => [907.09, 1275.59], :SRA4 => [637.80, 907.09], :LETTER => [612.00, 792.00], :LEGAL => [612.00, 1008.00], :FOLIO => [612.00, 936.00], :EXECUTIVE => [521.86, 756.00] }
- DEFAULT_CELL_PADDING =
3
Instance Attribute Summary collapse
-
#page ⇒ Object
readonly
Returns the value of attribute page.
Class Method Summary collapse
-
.open(output, options = {}) {|pdf| ... } ⇒ Object
convenience method, takes the same arguments as the constructor along with a block, and automatically finishes the PDF for you.
Instance Method Summary collapse
-
#absolute_bottom_margin ⇒ Object
Returns the y value of the bottom margin The top left corner of the page is (0,0).
-
#absolute_left_margin ⇒ Object
Returns the x value of the left margin The top left corner of the page is (0,0).
-
#absolute_right_margin ⇒ Object
Returns the x value of the right margin The top left corner of the page is (0,0).
-
#absolute_top_margin ⇒ Object
Returns the y value of the top margin The top left corner of the page is (0,0).
-
#absolute_x_middle ⇒ Object
Returns the x at the middle of the page.
-
#absolute_y_middle ⇒ Object
Returns the y at the middle of the page.
-
#body_height ⇒ Object
Returns the height of the usable part of the page (between the top and bottom margins).
-
#body_width ⇒ Object
Returns the width of the usable part of the page (between the side margins).
-
#body_x_middle ⇒ Object
Returns the x coordinate of the middle part of the usable space between the margins.
-
#body_y_middle ⇒ Object
Returns the y coordinate of the middle part of the usable space between the margins.
-
#cell(str, x, y, w, h, opts = {}) ⇒ Object
add text to the page, bounded by a box with dimensions HxW, with it’s top left corner at x,y.
-
#circle(x, y, r, options = {}) ⇒ Object
draw a circle with radius r and a centre point at (x,y).
-
#color(c) ⇒ Object
(also: #color=)
change the default colour used to draw on the canvas.
-
#current_point ⇒ Object
return the current position of the cursor returns 2 values - x,y.
-
#curve(x0, y0, x1, y1, x2, y2, x3, y3, options = {}) ⇒ Object
Adds a cubic Bezier spline to the path from the (x0, y0) to position (x3, y3) in user-space coordinates, using (x1, y1) and (x2, y2) as the control points.
- #default_text_options ⇒ Object
- #finish ⇒ Object
-
#finished? ⇒ Boolean
returns true if the PDF has already been rendered, false if it hasn’t.
-
#font(fontname, style = nil, weight = nil) ⇒ Object
change the default font to write with.
-
#font_size(size) ⇒ Object
(also: #font_size=)
Change the default font size.
-
#image(filename, opts = {}) ⇒ Object
add an image to the page - a wide range of image formats are supported, including svg, jpg, png and gif.
-
#indent(n) ⇒ Object
Moves right across the document by n, executes a block, then moves back left by the same amount.
-
#initialize(*args) ⇒ Wrapper
constructor
- create a new PDF::Wrapper class to compose a PDF document Params:
output
-
Where to render the PDF to.
- create a new PDF::Wrapper class to compose a PDF document Params:
-
#line(x0, y0, x1, y1, options = {}) ⇒ Object
draw a line from x1,y1 to x2,y2.
-
#line_width(f) ⇒ Object
(also: #line_width=)
change the default line width used to draw stroke on the canvas.
- #margin_bottom ⇒ Object
- #margin_left ⇒ Object
- #margin_right ⇒ Object
- #margin_top ⇒ Object
-
#move_down(n) ⇒ Object
move down the canvas by n points returns the new y position.
-
#move_left(n) ⇒ Object
move left across the canvas by n points returns the new x position.
-
#move_right(n) ⇒ Object
move right across the canvas by n points returns the new x position.
-
#move_to(x, y) ⇒ Object
move the cursor to an arbitary position on the current page.
-
#move_up(n) ⇒ Object
move up the canvas by n points returns the new y position.
-
#pad(n) ⇒ Object
Moves down the document by y, executes a block, then moves down the document by y again.
-
#pad_bottom(n) ⇒ Object
Executes a block then moves down the document.
-
#pad_top(n) ⇒ Object
Moves down the document and then executes a block.
- #page_height ⇒ Object
- #page_width ⇒ Object
-
#points_to_bottom_margin(starty) ⇒ Object
return the number of points from starty to the bottom border.
-
#points_to_right_margin(startx) ⇒ Object
return the number of points from startx to the right border.
-
#rectangle(x, y, w, h, options = {}) ⇒ Object
draw a rectangle starting at x,y with w,h dimensions.
-
#render ⇒ Object
render the PDF and return it as a string.
-
#render_file(filename) ⇒ Object
save the rendered PDF to a file.
-
#repeating_element(spec = :all, &block) ⇒ Object
add the same elements to multiple pages.
-
#reset_cursor ⇒ Object
reset the cursor by moving it to the top left of the useable section of the page.
-
#start_new_page(opts = {}) ⇒ Object
move to the next page.
-
#table(data, opts = {}) ⇒ Object
Draws a basic table of text on the page.
-
#text(str, opts = {}) ⇒ Object
Write text to the page.
-
#text_height(str, width, opts = {}) ⇒ Object
Returns the amount of vertical space needed to display the supplied text at the requested width opts is an options hash that specifies various attributes of the text.
-
#text_width(str, opts = {}) ⇒ Object
Returns the amount of horizontal space needed to display the supplied text with the requested options opts is an options hash that specifies various attributes of the text.
-
#translate(x, y, &block) ⇒ Object
Set a new location to be the origin (0,0).
- #x ⇒ Object
- #y ⇒ Object
Constructor Details
#initialize(*args) ⇒ Wrapper
create a new PDF::Wrapper class to compose a PDF document Params:
output
-
Where to render the PDF to. Can be a string containing a filename, or an IO object (File, StringIO, etc)
Options:
:paper
-
The paper size to use (default :A4). Can be a predefined paper size, or an array of [width, height]
:orientation
-
:portrait (default) or :landscape
:background_color
-
The background colour to use (default :white)
:margin_top
-
The size of the default top margin (default 5% of page)
:margin_bottom
-
The size of the default bottom margin (default 5% of page)
:margin_left
-
The size of the default left margin (default 5% of page)
:margin_right
-
The size of the default right margin (default 5% of page)
:template
-
The path to an image file. If specified, the first page of the document will use the specified image as a template. The page will be sized to match the template size. The use templates on subsequent pages, see the options for start_new_page.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/pdf/wrapper.rb', line 126 def initialize(*args) # TODO: Investigate ways of using the cairo transform/translate/scale functionality to # reduce the amount of irritating co-ordinate maths the user of PDF::Wrapper (ie. me!) # is required to do. # - translate the pdf body width so that it's 1.0 wide and 1.0 high? # TODO: find a way to add metadata (title, author, subject, etc) to the output file # currently no way to specify this in cairo. # tentatively scheduled for cairo 1.10 - see: # - http://cairographics.org/roadmap/ # - http://lists.cairographics.org/archives/cairo/2007-September/011441.html # - http://lists.freedesktop.org/archives/cairo/2006-April/006809.html if args.size == 0 opts = {} output = StringIO.new warn "WARNING: deprecated call to PDF::Wrapper constructor. Check API documentation on new compulsory parameter" elsif args.size == 1 if args.first.kind_of?(Hash) opts = *args output = StringIO.new warn "WARNING: deprecated call to PDF::Wrapper constructor. Check API documentation on new compulsory parameter" else output = args.first opts = {} end elsif args.size == 2 output, opts = *args else raise ArgumentError, 'Invalid parameters passed to constructor' end = {:paper => :A4, :orientation => :portrait, :background_color => :white } .merge!(opts) # test for invalid options .assert_valid_keys(:paper, :orientation, :background_color, :margin_left, :margin_right, :margin_top, :margin_bottom, :io, :template) set_dimensions([:orientation], [:paper]) # set page margins and dimensions of usable canvas @margin_left = [:margin_left] || (@page_width * 0.05).ceil @margin_right = [:margin_right] || (@page_width * 0.05).ceil @margin_top = [:margin_top] || (@page_height * 0.05).ceil @margin_bottom = [:margin_bottom] || (@page_height * 0.05).ceil # initialize some cairo objects to draw on @output = output @surface = Cairo::PDFSurface.new(@output, @page_width, @page_height) @context = Cairo::Context.new(@surface) # set the background colour color([:background_color]) @context.paint # set a default drawing colour and font style color(:black) line_width(0.5) font("Sans Serif") font_size(16) # maintain a count of pages and array of repeating elements to add to each page @page = 1 @repeating = [] # build the first page from a template if required if opts[:template] w, h = image_dimensions(opts[:template]) @surface.set_size(w, h) image(opts[:template], :left => 0, :top => 0) end # move the cursor to the top left of the usable canvas reset_cursor end |
Instance Attribute Details
#page ⇒ Object (readonly)
Returns the value of attribute page.
79 80 81 |
# File 'lib/pdf/wrapper.rb', line 79 def page @page end |
Class Method Details
Instance Method Details
#absolute_bottom_margin ⇒ Object
Returns the y value of the bottom margin The top left corner of the page is (0,0)
243 244 245 |
# File 'lib/pdf/wrapper.rb', line 243 def absolute_bottom_margin page_height - margin_bottom end |
#absolute_left_margin ⇒ Object
Returns the x value of the left margin The top left corner of the page is (0,0)
225 226 227 |
# File 'lib/pdf/wrapper.rb', line 225 def absolute_left_margin margin_left end |
#absolute_right_margin ⇒ Object
Returns the x value of the right margin The top left corner of the page is (0,0)
231 232 233 |
# File 'lib/pdf/wrapper.rb', line 231 def absolute_right_margin page_width - margin_right end |
#absolute_top_margin ⇒ Object
Returns the y value of the top margin The top left corner of the page is (0,0)
237 238 239 |
# File 'lib/pdf/wrapper.rb', line 237 def absolute_top_margin margin_top end |
#absolute_x_middle ⇒ Object
Returns the x at the middle of the page
248 249 250 |
# File 'lib/pdf/wrapper.rb', line 248 def absolute_x_middle page_width / 2 end |
#absolute_y_middle ⇒ Object
Returns the y at the middle of the page
253 254 255 |
# File 'lib/pdf/wrapper.rb', line 253 def absolute_y_middle page_height / 2 end |
#body_height ⇒ Object
Returns the height of the usable part of the page (between the top and bottom margins)
263 264 265 266 |
# File 'lib/pdf/wrapper.rb', line 263 def body_height #@context.device_to_user(@page_width - @margin_left - @margin_right, @page_height - @margin_top - @margin_bottom).last device_y_to_user_y(@page_height - @margin_top - @margin_bottom) end |
#body_width ⇒ Object
Returns the width of the usable part of the page (between the side margins)
258 259 260 |
# File 'lib/pdf/wrapper.rb', line 258 def body_width device_x_to_user_x(@page_width - @margin_left - @margin_right) end |
#body_x_middle ⇒ Object
Returns the x coordinate of the middle part of the usable space between the margins
269 270 271 |
# File 'lib/pdf/wrapper.rb', line 269 def body_x_middle margin_left + (body_width / 2) end |
#body_y_middle ⇒ Object
Returns the y coordinate of the middle part of the usable space between the margins
274 275 276 |
# File 'lib/pdf/wrapper.rb', line 274 def body_y_middle margin_top + (body_height / 2) end |
#cell(str, x, y, w, h, opts = {}) ⇒ Object
add text to the page, bounded by a box with dimensions HxW, with it’s top left corner at x,y. Any text that doesn’t fit it the box will be silently dropped.
In addition to the standard text style options (see the documentation for text()), cell() supports the following options:
:border
-
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.
:border_width
-
How wide should the border be?
:border_color
-
What color should the border be?
:fill_color
-
A background color for the cell. Defaults to none.
:radius
-
Give the border around the cell rounded corners. Implies :border => “tblr”
Unlike with the text() method, the :font_size argument can be a range. The largest size in the range that will fit all the text in the cell will be used.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/pdf/wrapper/text.rb', line 61 def cell(str, x, y, w, h, opts={}) # TODO: add a wrap option so wrapping can be disabled # TODO: add an option for vertical alignment # TODO: allow cell contents to be defined as a block, like link_to in EDGE rails = .merge!({:border => "tblr", :border_width => @default_line_width, :border_color => :black, :fill_color => nil, :padding => DEFAULT_CELL_PADDING, :radius => nil}) .merge!(opts) .assert_valid_keys(.keys + [:width, :border, :border_width, :border_color, :fill_color, :padding, :radius]) if [:font_size] && [:font_size].is_a?(Range) [:font_size] = best_font_size(str, w, h, [:font_size], ) end # apply padding textw = w - ([:padding] * 2) texth = h - ([:padding] * 2) # if the user wants a rounded rectangle, we'll draw the border with a rectangle instead # of 4 lines [:border] = nil if [:radius] # normalise the border [:border] = "" unless [:border] [:border].downcase! save_coords do translate(x, y) do # draw a border around the cell if [:radius] rectangle(0,0,w,h, :radius => [:radius], :color => [:border_color], :fill_color => [:fill_color], :line_width => [:border_width]) else rectangle(0,0,w,h, :color => [:fill_color], :fill_color => [:fill_color]) if [:fill_color] line(0,0,w,0, :color => [:border_color], :line_width => [:border_width]) if [:border].include?("t") line(0,h,w,h, :color => [:border_color], :line_width => [:border_width]) if [:border].include?("b") line(0,0,0,h, :color => [:border_color], :line_width => [:border_width]) if [:border].include?("l") line(w,0,w,h, :color => [:border_color], :line_width => [:border_width]) if [:border].include?("r") end layout = build_pango_layout(str.to_s, textw, ) color([:color]) if [:color] # draw the context on our cairo layout render_layout(layout, [:padding], [:padding], texth) end end end |
#circle(x, y, r, options = {}) ⇒ Object
draw a circle with radius r and a centre point at (x,y). Parameters:
:x
-
The x co-ordinate of the circle centre.
:y
-
The y co-ordinate of the circle centre.
:r
-
The radius of the circle
Options:
:color
-
The colour of the circle outline
:line_width
-
The width of outline. Defaults to 0.5
:fill_color
-
The colour to fill the circle with. Defaults to nil (no fill)
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/pdf/wrapper/graphics.rb', line 14 def circle(x, y, r, = {}) .assert_valid_keys(:color, :line_width, :fill_color) save_coords_and_state do move_to(x + r, y) # if the circle should be filled in if [:fill_color] @context.save do color([:fill_color]) @context.circle(x, y, r).fill end end color([:color]) if [:color] line_width([:line_width]) if [:line_width] @context.circle(x, y, r).stroke end end |
#color(c) ⇒ Object Also known as: color=
change the default colour used to draw on the canvas
Parameters:
c
-
either a colour symbol recognised by rcairo (:red, :blue, :black, etc) or an array with 3-4 integer elements. The first 3 numbers are red, green and blue (0-255). The optional 4th number is the alpha channel and should be between 0 and 1. See the API docs at cairo.rubyforge.org/ for a list of predefined colours
361 362 363 364 365 |
# File 'lib/pdf/wrapper.rb', line 361 def color(c) c = translate_color(c) validate_color(c) @context.set_source_rgba(*c) end |
#current_point ⇒ Object
return the current position of the cursor returns 2 values - x,y
288 289 290 |
# File 'lib/pdf/wrapper.rb', line 288 def current_point @context.current_point end |
#curve(x0, y0, x1, y1, x2, y2, x3, y3, options = {}) ⇒ Object
Adds a cubic Bezier spline to the path from the (x0, y0) to position (x3, y3) in user-space coordinates, using (x1, y1) and (x2, y2) as the control points. Options:
:color
-
The colour of the line
:line_width
-
The width of line. Defaults to 0.5
65 66 67 68 69 70 71 72 73 74 |
# File 'lib/pdf/wrapper/graphics.rb', line 65 def curve(x0, y0, x1, y1, x2, y2, x3, y3, = {}) .assert_valid_keys(:color, :line_width) save_coords_and_state do color([:color]) if [:color] line_width([:line_width]) if [:line_width] move_to(x0,y0) @context.curve_to(x1, y1, x2, y2, x3, y3).stroke end end |
#default_text_options ⇒ Object
213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/pdf/wrapper/text.rb', line 213 def { :font => @default_font, :font_size => @default_font_size, :alignment => :left, :wrap => :wordchar, :justify => false, :spacing => 0, :color => nil, :markup => nil } end |
#finish ⇒ Object
521 522 523 524 525 526 527 528 529 530 531 532 |
# File 'lib/pdf/wrapper.rb', line 521 def finish # finalise the document @context.show_page @context.target.finish #@output.close if io_output? @surface.finish #@surface.destroy #@context.destroy self rescue Cairo::SurfaceFinishedError # do nothing, we're happy that the surfaced has been finished end |
#finished? ⇒ Boolean
returns true if the PDF has already been rendered, false if it hasn’t. Due to limitations of the underlying libraries, content cannot be added to a PDF once it has been rendered.
538 539 540 541 542 543 544 545 546 |
# File 'lib/pdf/wrapper.rb', line 538 def finished? if io_output? @output.seek(@output.size - 6) bytes = @output.read(6) else bytes = @output[-6,6] end bytes == "%%EOF\n" ? true : false end |
#font(fontname, style = nil, weight = nil) ⇒ Object
change the default font to write with
40 41 42 43 44 |
# File 'lib/pdf/wrapper/text.rb', line 40 def font(fontname, style = nil, weight = nil) @default_font = fontname @default_font_style = style unless style.nil? @default_font_weight = weight unless weight.nil? end |
#font_size(size) ⇒ Object Also known as: font_size=
Change the default font size
If no block is provided, the change is permanent. If a block is provided, the change will revert at the end of the block
Permanant change:
pdf.font_size 10
Temporary change:
pdf.font_size 20
pdf.text "This text is size 20"
pdf.font_size(10) do
pdf.text "This text is size 20"
end
pdf.text "This text is size 20"
24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/pdf/wrapper/text.rb', line 24 def font_size(size) new_size = size.to_i raise ArgumentError, 'font size must be > 0' if new_size <= 0 if block_given? orig_size = @default_font_size @default_font_size = new_size yield @default_font_size = orig_size else @default_font_size = new_size end end |
#image(filename, opts = {}) ⇒ Object
add an image to the page - a wide range of image formats are supported, including svg, jpg, png and gif. PDF images are also supported - an attempt to add a multipage PDF will result in only the first page appearing in the new document.
supported options:
:left
-
The x co-ordinate of the left-hand side of the image.
:top
-
The y co-ordinate of the top of the image.
:height
-
The height of the image
:width
-
The width of the image
:proportional
-
Boolean. Maintain image proportions when scaling. Defaults to false.
:padding
-
Add some padding between the image and the specified box.
:position
-
(:left, :center, :right) If the image size is scaled down, sets the horizontal position.
:vposition
-
(:top, :middle, :bottom) If the image size is scaled down, sets the vertical position.
:rotate
-
The desired rotation. One of :counterclockwise, :upsidedown, :clockwise. Doesn’t work with PNG, PDF or SVG files.
left and top default to the current cursor location width and height default to the size of the imported image padding defaults to 0
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/pdf/wrapper/images.rb', line 23 def image(filename, opts = {}) # TODO: add some options for justification and padding raise ArgumentError, "file #{filename} not found" unless File.file?(filename) opts.assert_valid_keys(.keys + [:padding, :proportional, :position, :vposition, :rotate]) if opts[:padding] opts[:left] += opts[:padding].to_i if opts[:left] opts[:top] += opts[:padding].to_i if opts[:top] opts[:width] -= opts[:padding].to_i * 2 if opts[:width] opts[:height] -= opts[:padding].to_i * 2 if opts[:height] end case detect_image_type(filename) when :pdf then draw_pdf filename, opts when :png then draw_png filename, opts when :svg then draw_svg filename, opts else draw_pixbuf filename, opts end end |
#indent(n) ⇒ Object
Moves right across the document by n, executes a block, then moves back left by the same amount
pdf.text "some text"
pdf.indent(50) do
pdf.text "This starts 50 points right the previous line of text"
end
pdf.text "This starts in line with the first line of text"
If no block is provided, operates just like move_right.
501 502 503 504 505 506 507 508 509 |
# File 'lib/pdf/wrapper.rb', line 501 def indent(n) if block_given? move_right n yield move_left n else move_right n end end |
#line(x0, y0, x1, y1, options = {}) ⇒ Object
draw a line from x1,y1 to x2,y2
Options:
:color
-
The colour of the line
:line_width
-
The width of line. Defaults its 0.5
39 40 41 42 43 44 45 46 47 48 |
# File 'lib/pdf/wrapper/graphics.rb', line 39 def line(x0, y0, x1, y1, = {}) .assert_valid_keys(:color, :line_width) save_coords_and_state do color([:color]) if [:color] line_width([:line_width]) if [:line_width] move_to(x0,y0) @context.line_to(x1,y1).stroke end end |
#line_width(f) ⇒ Object Also known as: line_width=
change the default line width used to draw stroke on the canvas
Parameters:
f
-
float value of stroke width from 0.01 to 255
54 55 56 57 |
# File 'lib/pdf/wrapper/graphics.rb', line 54 def line_width(f) @line_width = f @context.set_line_width @context.device_to_user_distance(f,f).max end |
#margin_bottom ⇒ Object
300 301 302 |
# File 'lib/pdf/wrapper.rb', line 300 def margin_bottom device_y_to_user_y(@margin_bottom).to_i end |
#margin_left ⇒ Object
304 305 306 |
# File 'lib/pdf/wrapper.rb', line 304 def margin_left device_x_to_user_x(@margin_left).to_i end |
#margin_right ⇒ Object
308 309 310 |
# File 'lib/pdf/wrapper.rb', line 308 def margin_right device_x_to_user_x(@margin_right).to_i end |
#margin_top ⇒ Object
312 313 314 |
# File 'lib/pdf/wrapper.rb', line 312 def margin_top device_y_to_user_y(@margin_top).to_i end |
#move_down(n) ⇒ Object
move down the canvas by n points returns the new y position
408 409 410 411 412 413 |
# File 'lib/pdf/wrapper.rb', line 408 def move_down(n) x, y = current_point newy = y + n move_to(x, newy) newy end |
#move_left(n) ⇒ Object
move left across the canvas by n points returns the new x position
428 429 430 431 432 433 |
# File 'lib/pdf/wrapper.rb', line 428 def move_left(n) x, y = current_point newx = x - n move_to(newx, y) newx end |
#move_right(n) ⇒ Object
move right across the canvas by n points returns the new x position
438 439 440 441 442 443 |
# File 'lib/pdf/wrapper.rb', line 438 def move_right(n) x, y = current_point newx = x + n move_to(newx, y) newx end |
#move_to(x, y) ⇒ Object
move the cursor to an arbitary position on the current page
512 513 514 |
# File 'lib/pdf/wrapper.rb', line 512 def move_to(x,y) @context.move_to(x,y) end |
#move_up(n) ⇒ Object
move up the canvas by n points returns the new y position
418 419 420 421 422 423 |
# File 'lib/pdf/wrapper.rb', line 418 def move_up(n) x, y = current_point newy = y - n move_to(x, newy) newy end |
#pad(n) ⇒ Object
Moves down the document by y, executes a block, then moves down the document by y again.
pdf.text "some text"
pdf.pad(100) do
pdf.text "This is 100 points below the previous line of text"
end
pdf.text "This is 100 points below the previous line of text"
480 481 482 483 484 485 486 487 488 |
# File 'lib/pdf/wrapper.rb', line 480 def pad(n) if block_given? move_down n yield move_down n else move_down n end end |
#pad_bottom(n) ⇒ Object
Executes a block then moves down the document
pdf.text "some text"
pdf.pad_bottom(100) do
pdf.text "This text appears right below the previous line of text"
end
pdf.text "This is 100 points below the previous line of text"
466 467 468 469 |
# File 'lib/pdf/wrapper.rb', line 466 def pad_bottom(n) yield move_down n end |
#pad_top(n) ⇒ Object
Moves down the document and then executes a block.
pdf.text "some text"
pdf.pad_top(100) do
pdf.text "This is 100 points below the previous line of text"
end
pdf.text "This text appears right below the previous line of text"
453 454 455 456 |
# File 'lib/pdf/wrapper.rb', line 453 def pad_top(n) move_down n yield end |
#page_height ⇒ Object
278 279 280 |
# File 'lib/pdf/wrapper.rb', line 278 def page_height device_y_to_user_y(@page_height) end |
#page_width ⇒ Object
282 283 284 |
# File 'lib/pdf/wrapper.rb', line 282 def page_width device_x_to_user_x(@page_width) end |
#points_to_bottom_margin(starty) ⇒ Object
return the number of points from starty to the bottom border
317 318 319 |
# File 'lib/pdf/wrapper.rb', line 317 def points_to_bottom_margin(starty) absolute_bottom_margin - starty end |
#points_to_right_margin(startx) ⇒ Object
return the number of points from startx to the right border
322 323 324 |
# File 'lib/pdf/wrapper.rb', line 322 def points_to_right_margin(startx) absolute_right_margin - startx end |
#rectangle(x, y, w, h, options = {}) ⇒ Object
draw a rectangle starting at x,y with w,h dimensions. Parameters:
:x
-
The x co-ordinate of the top left of the rectangle.
:y
-
The y co-ordinate of the top left of the rectangle.
:w
-
The width of the rectangle
:h
-
The height of the rectangle
Options:
:color
-
The colour of the rectangle outline
:line_width
-
The width of outline. Defaults to 0.5
:fill_color
-
The colour to fill the rectangle with. Defaults to nil (no fill)
:radius
-
If specified, the rectangle will have rounded corners with the specified radius
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/pdf/wrapper/graphics.rb', line 88 def rectangle(x, y, w, h, = {}) .assert_valid_keys(:color, :line_width, :fill_color, :radius) save_coords_and_state do # if the rectangle should be filled in if [:fill_color] @context.save do color([:fill_color]) if [:radius] @context.rounded_rectangle(x, y, w, h, [:radius]).fill else @context.rectangle(x, y, w, h).fill end end end color([:color]) if [:color] line_width([:line_width]) if [:line_width] if [:radius] @context.rounded_rectangle(x, y, w, h, [:radius]).stroke else @context.rectangle(x, y, w, h).stroke end end end |
#render ⇒ Object
render the PDF and return it as a string
373 374 375 376 377 378 379 380 381 382 383 |
# File 'lib/pdf/wrapper.rb', line 373 def render # TODO: remove this method at some point. Deprecation started on 15th September 2008 warn "WARNING: render() is deprecated. See documentation for PDF::Wrapper#initialize for more information" finish case @output when StringIO then return @output.string when File then return File.read(@output.path) else return File.read(@output) end end |
#render_file(filename) ⇒ Object
save the rendered PDF to a file
386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/pdf/wrapper.rb', line 386 def render_file(filename) # TODO: remove this method at some point. Deprecation started on 15th September 2008 warn "WARNING: render_file() is deprecated. See documentation for PDF::Wrapper#initialize for more information" finish case @output when StringIO then File.open(filename, "w") do |of| of.write(@output.string) end when File then return FileUtils.cp(@output.path, filename) else return FileUtils.cp(@output, filename) end end |
#repeating_element(spec = :all, &block) ⇒ Object
add the same elements to multiple pages. Useful for adding items like headers, footers and watermarks.
There is a single block parameter that is a proxy to the current PDF::Wrapper object that disallows start_new_page calls. Every other method from PDF::Wrapper is considered valid.
arguments:
spec
-
Which pages to add the items to. :all, :odd, :even, a range, an Array of numbers or an number
To add text to every page that mentions the page number
pdf.repeating_element(:all) do |page|
page.text("Page #{page.page}!", :left => page.margin_left, :top => page.margin_top, :font_size => 18)
end
To add a circle to the middle of every page
pdf.repeating_element(:all) do |page|
page.circle(page.absolute_x_middle, page.absolute_y_middle, 100)
end
567 568 569 570 571 572 |
# File 'lib/pdf/wrapper.rb', line 567 def repeating_element(spec = :all, &block) call_repeating_element(spec, block) # store it so we can add it to future pages @repeating << {:spec => spec, :block => block} end |
#reset_cursor ⇒ Object
reset the cursor by moving it to the top left of the useable section of the page
517 518 519 |
# File 'lib/pdf/wrapper.rb', line 517 def reset_cursor @context.move_to(margin_left,margin_top) end |
#start_new_page(opts = {}) ⇒ Object
move to the next page
options:
:paper
-
The paper size to use (default: same as the previous page)
:orientation
-
:portrait or :landscape (default: same as the previous page)
:pageno
-
If specified, the current page number will be set to that. By default, the page number will just increment.
:template
-
The path to an image file. If specified, the new page will use the specified image as a template. The page will be sized to match the template size
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 |
# File 'lib/pdf/wrapper.rb', line 582 def start_new_page(opts = {}) opts.assert_valid_keys(:paper, :orientation, :pageno, :template) set_dimensions(opts[:orientation], opts[:paper]) @context.show_page if opts[:template] w, h = image_dimensions(opts[:template]) @surface.set_size(w, h) image(opts[:template], :left => 0, :top => 0) else @surface.set_size(@page_width, @page_height) end # reset or increment the page counter if opts[:pageno] @page = opts[:pageno].to_i else @page += 1 end # move the cursor to the top left of our page body reset_cursor # apply the appropriate repeating elements to the new page @repeating.each do |repeat| call_repeating_element(repeat[:spec], repeat[:block]) end end |
#table(data, opts = {}) ⇒ Object
Draws a basic table of text on the page. See the documentation for PDF::Wrapper::Table to get a detailed description of how to control the table and its appearance. If data is an array, it can contain Cell-like objects (see PDF::Wrapper::TextCell and PDF::Wrapper::TextImageCell) or any objects that respond to to_s().
data
-
a 2d array with the data for the columns, or a PDF::Wrapper::Table object
Options
The only options available when rendering a table are those relating to its size and location. All other options that relate to the content of the table and how it looks should be configured on the PDF::Wrapper::Table object that is passed into this function.
:left
-
The x co-ordinate of the left-hand side of the table. Defaults to the current cursor location
:top
-
The y co-ordinate of the top of the text. Defaults to the current cursor location
:width
-
The width of the table. Defaults to the distance from the left of the table to the right margin
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/pdf/wrapper/table.rb', line 20 def table(data, opts = {}) # TODO: add support for a table footer # - repeating each page, or just at the bottom? # - if it repeats, should it be different on each page? ie. a sum of that pages rows, etc. # TODO: maybe support for multiple data sets with group headers/footers. useful for subtotals, etc x, y = current_point = {:left => x, :top => y } .merge!(opts) .assert_valid_keys(.keys) if data.kind_of?(::PDF::Wrapper::Table) t = data else t = ::PDF::Wrapper::Table.new do |table| table.data = data end end t.width = [:width] || points_to_right_margin([:left]) t.draw(self, [:left], [:top]) end |
#text(str, opts = {}) ⇒ Object
Write text to the page
By default the text will be rendered using all the space within the margins and using the default font styling set by font(), font_size, etc
There is no way to place a bottom bound (or height) onto the text. Text will wrap as necessary and take all the room it needs. For finer grained control of text boxes, see the cell method.
To override all these defaults, use the options hash
Positioning Options:
:left
-
The x co-ordinate of the left-hand side of the text.
:top
-
The y co-ordinate of the top of the text.
:width
-
The width of the text to wrap at
Text Style Options:
:font
-
The font family to use as a string
:font_size
-
The size of the font in points
:alignment
-
Align the text along the left, right or centre. Use :left, :right, :center
:wrap
-
The wrapping technique to use if required. Use :word, :char or :wordchar. Default is :wordchar
:justify
-
Justify the text so it exapnds to fill the entire width of each line. Note that this only works in pango >= 1.17
:spacing
-
Space between lines in PDF points
:markup
-
Interpret the text as a markup language. Default is nil (none).
Markup
If the markup option is specified, the text can be modified in various ways. At this stage the only markup syntax implemented is :pango.
Pango Markup
Full details on the Pango markup language are avaialble at ruby-gnome2.sourceforge.jp/hiki.cgi?pango-markup
The format is vaguely XML-like.
Bold: “Some of this text is bold.” Italics: “Some of this text is in italics.” Strikethrough: “My name is <s>Bob</s>James.” Monospace Font: “Code:nputs 1
.”
For more advanced control, use span tags
Big and Bold: Some of this text is <span weight=“bold” font_desc=“20”>bold</span>. Stretched: Some of this text is <span stretch=“extraexpanded”>funny looking</span>.
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/pdf/wrapper/text.rb', line 159 def text(str, opts={}) # TODO: add converters from various markup languages to pango markup. (markdown, textile, etc) # TODO: add a wrap option so wrapping can be disabled # # the non pango way to add text to the cairo context, not particularly useful for # PDF generation as it doesn't support wrapping text or other advanced layout features # and I really don't feel like re-implementing all that # @context.show_text(str) # the "pango way" x, y = current_point = .merge!({:left => x, :top => y}) .merge!(opts) .assert_valid_keys(.keys + .keys) # if the user hasn't specified a width, make the text wrap on the right margin [:width] = absolute_right_margin - [:left] if [:width].nil? layout = build_pango_layout(str.to_s, [:width], ) color([:color]) if [:color] # draw the context on our cairo layout y = render_layout(layout, [:left], [:top]) move_to([:left], y) end |
#text_height(str, width, opts = {}) ⇒ Object
Returns the amount of vertical space needed to display the supplied text at the requested width opts is an options hash that specifies various attributes of the text. See the text function for more information.
189 190 191 192 193 194 195 196 197 198 |
# File 'lib/pdf/wrapper/text.rb', line 189 def text_height(str, width, opts = {}) = .merge(opts) .assert_valid_keys(.keys) [:width] = width || body_width layout = build_pango_layout(str.to_s, [:width], ) width, height = layout.size return height / Pango::SCALE end |
#text_width(str, opts = {}) ⇒ Object
Returns the amount of horizontal space needed to display the supplied text with the requested options opts is an options hash that specifies various attributes of the text. See the text function for more information. The text is assumed to not wrap.
203 204 205 206 207 208 209 210 211 |
# File 'lib/pdf/wrapper/text.rb', line 203 def text_width(str, opts = {}) = .merge(opts) .assert_valid_keys(.keys) layout = build_pango_layout(str.to_s, -1, ) width, height = layout.size return width / Pango::SCALE end |
#translate(x, y, &block) ⇒ Object
Set a new location to be the origin (0,0). This is useful for repetitive tasks where objects need to be added to the canvas at regular offsets, and can save a significant amount of irritating co-ordinate maths.
As an example, consider the following code fragment. If you have a series of images to arrange on a page with identical sizes, translate can help keep the code clean and readable by reducing (or removing completely) the need to perform a series of basic sums to calculate the correct offsets, etc.
def (filename, , x, y)
@pdf.translate(x, y) do
@pdf.image(filename, :top => 0, :left => 0, :height => 100, :width => 100, :proportional => true)
@pdf.text(, :top => 110, :left => 0, :width => 100)
end
end
("orc.svg", "Orc", 100, 100)
("hobbit.svg", "Hobbit", 100, 400)
("elf.svg", "Elf", 100, 400)
345 346 347 348 349 350 351 |
# File 'lib/pdf/wrapper.rb', line 345 def translate(x, y, &block) @context.save do @context.translate(x, y) move_to(0,0) yield end end |
#x ⇒ Object
292 293 294 |
# File 'lib/pdf/wrapper.rb', line 292 def x @context.current_point.first end |
#y ⇒ Object
296 297 298 |
# File 'lib/pdf/wrapper.rb', line 296 def y @context.current_point.last end |