Thursday, November 20, 2008

Prawnto, Generating PDF in Rails Applications

Rails wiki lists a number of libraries that can be used to generate PDF files in ruby. Prawnto was very suitable for my need (generating PDF files that contain text with differentfont-size and adding some formatting). Prawn is able to generate more complex PDF documents including adding photos. You can check the installation steps online

Prawnto requires you to add code to your controller and to a .prawn layout file. There are several demos available online and can be used as guidance.

Below is an example for generating a PDF format of an article. The article has a title and an array of blocks, each block has title and content. The controller code is:

def show
   @title="My Article"
   @blocks= [
         {:title=>'Block One', :content=>'content one'},
         {:title=>'Block Two', :content=>'content two'},
         {:title=>'Block Three', :content=>'content three'},
         {:title=>'Block Four', :content=>'content four'}]
   prawnto :prawn => {
      :page_size => 'A4',
      :left_margin => 50,
      :right_margin => 50,
      :top_margin => 24,
      :bottom_margin => 24},
      :filename=>"#{@title.gsub(' ','_')}.pdf"
   render :layout=>false
end

In the view file of a prawnto action, we should use the pdf object. that has several basic methods to plot our PDF file. those include:

  • pdf.text("text to be written", :size=>15) #writing some text with a specific size
  • pdf.font("Helvetica") #setting font
  • pdf.stroke{line([x1,y1], [x2,y2])} #drawing a line
  • pdf.table(data_array, options) # to draw a table containing array of string arrays (data)

I used instance_eval that i described in my earlier post to create a higher level methods to increase the readibility of the view file.

pdf.font "Helvetica"
pdf.instance_eval do
   def font_size; {:title=>20, :subtitle=>16, :text=>10} end
   def write(some_text, style=:text)
      text some_text, :size=>font_size[style]
   end
   def separator
      write " ", :text
      stroke {y=@y-25; line [1,y], [bounds.width,y]}
      write " ", :text
   end
end

pdf.write "#{@title}", :title
@blocks.each do |block|
   pdf.separator
   pdf.write block[:title], :subtitle
   pdf.write block[:content], :text
end

Creating the higher level methods made writing the real data easier. Now you just call separator to draw a horizontal line, instead of worrying about the corresponding coordinates.

2 comments:

jpemberthy said...

Thanks! so much

mahmoud said...

@jpemberthy
You are welcome. I Believe Prawnto is a very usable and useful plugin for a lot of people out there.. and I do like to thank the prawnto team, they did a great work