BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Ruby PDF Generation Made Easier and Cleaner with Prawn.

Ruby PDF Generation Made Easier and Cleaner with Prawn.

This item in japanese

Bookmarks
There are several existing ways to generate PDF with Ruby (and Rails). Unsatisfied with existing solutions, Gregory Brown decided to design his own library which uses a DSL approach. Prawn is also supposed to be faster than other Ruby PDF libraries.

Once installed you'll be able to generate easily PDF with a DSL-ish approach (example excerpted from a Prawn sample) :
Prawn::Document.generate("image.pdf", :page_layout => :landscape) do

text 'Welcome in Prawn!', :at => [50,525]

pigs = "data/images/dice.png"
image pigs, :at => [50,450], :scale => 0.5

ruport = "data/images/ruport_transparent.png"
image ruport, :at => [50,525]

end
With this quick sample you'll end up with PDF output looking like this:

Generated PDF

Prawn will definitely be interesting in the Rails / Ruport world, and PDF::Writer is going to be replaced by Prawn in Edge Ruport very soon.

The Prawn release was the perfect opportunity to catch up with Gregory as he founded a community funded development venture: Ruby Mendicant. 6 months ago, Gregory made a call for participation for an open source project he would be dedicated to for the next 6 months. After raising more than 10000$, Gregory selected Prawn as the project he would concentrate on.

InfoQ: Is Prawn Yet Another PDF library? 
Gregory Brown: Prawn is significantly different than other Ruby PDF solutions, as it isn't a port of a library from another language, nor is it a wrapper on top of a lower level library.  We're not really extensively researching the other solutions out there, except when we need to consider specific aspects of things, so I doubt we'll turn up creating a carbon copy of some random PDF library out there.  We hope that this is a good thing, and that it leads to a solution that feels natural in its setting.

What lead you to write it?
Given the available time thanks to the Ruby Mendicant project, I knew I could tackle a hard problem. The PDF spec is over 1300 pages long, and although only part of that is dedicated to the generation side of things, it's a daunting task that is unlikely to be easily accomplished in someone's spare time. Since I have a serious need for a pleasant PDF library to work with, it gives me a lot of motivation to head down this read. The catalyst was mainly a post from James Gray, which suggested that we'd end up spending less effort overall by writing a new library rather than maintaining PDF::Writer for the long run. You can check that out here.

Why did you abandon PDF::Writer?
I didn't. Technically speaking, I'm still the active maintainer and will apply patches to fix critical bugs and get out maintenance releases until Prawn is widely adopted. The only decision I've made at this point is that there will be no PDF::Writer 1.2, at least not through my efforts. Michael Milner and I took over PDF::Writer from Austin Ziegler a few months ago, but only because no one else would take the job, and there were lots of bug fixes that have been collecting dust for several years that needed to be applied. We got out a few maintenance releases, and that has made PDF::Writer better.

But there is a reason PDF::Writer wasn't able to find a maintainer, and that is because the code is largely unmaintainable. Despite the fact that the library was good for its time, it is not possible to extend or repair without major hurdles. This is why I believe Prawn will be the way forward, it has a chance to avoid some of the pitfalls that would have been hard to see the first time around while developing PDF::Writer.

Prawn is supposed to be more performant?  
It is much faster for table rendering.  This is mainly because of algorithmic difference, the library itself has not yet been optimized at all for the small things.  However, these algorithmic differences can add up to orders of magnitude speed boosts, which no one can complain about. ;)

Do you have some benchmarks?
We have one distributed with the source that compares Prawn and PDF writer for nearly identical output of an 1833 record, 2 column table. On my machine, this takes about 3.5s to run on Prawn, and about 90-100s on PDF::Writer. As you increase the data size, the gap widens.

James Healy had a benchmark doing the same thing for PDF::Wrapper, a library that wraps Cairo bindings. Amazingly, Prawn was a hair faster because he was doing his pre-processing in Ruby and the stuff we were doing in Prawn was slightly more efficient.  The libraries are probably comparable in performance now that new features were added, but I didn't ever run these myself.

I also heard reports than Prawn is much faster than FPDF, a port of a PHP library of the same name, but I haven't benchmarked there. One user mentioned that his invoice generation code that previously took over 3 minutes to run was taking about 37s on Prawn.

Can you compete with other lower-level library?
I really haven't benchmarked against C libraries or anything of the like.  I think the goal is to make Prawn 'fast for Ruby' and 'fast enough to be useful'.  I have the goal in mind of keeping Prawn pure Ruby, and also keeping the code as readable as possible, so I won't be sacrificing those in the name of squeezing out every last bit of performance.  However, users can be sure we'll keep an eye on performance and make it so PDF is not the bottleneck that forces them to code outside of Ruby.

Can you compete with other languages libraries?
When researching for Prawn, I looked at the two other languages I'm most comfortable with: Perl and Python. I have to be honest and say neither language provided solutions I was terribly impressed with. Although Prawn tries to stay simple and core-functionality centric, I feel like it has a much nicer interface than any library I could find in these other languages.

Of course, I've been doing much more Ruby than I have been doing Perl or Python lately, so I may have missed something obvious. If so, I really want to know so I can go steal as many good ideas as possible.

Can you tell us more on Ruby Mendicant venture initiated 6 months ago?
It was basically a whim. I wrote a post to the O'Reilly blog during a moment of feeling stressed out and annoyed by my contracting work. It basically suggested I wanted to take some time off from work to hack on open source exclusively. Some people took me seriously and when enough people voiced their support, I threw up a Pledgie campaign for donations. A month later, I had 22 weeks of funding, and that's how the Ruby Mendicant project started.

Why did you choose to work on PDF generation as first project?
PDF generation is one of the few ideas I had. The next most popular among the community was doing a dedicated documentation effort, where I'd hit a bunch of libraries and spruce up the rdoc and maybe write some tutorials. PDF turned out to have more popular support, and people liked it because it was a single, unified goal. Since it's
something I really need, it was relatively easy to stay motivated, so I think it was a good pick.

What are you plans in the near future?
In the near future, Prawn will be able to do basic inline styling. We're also going to add some additional features to our image support that allows you to scale an image to fit in a box while preserving the aspect ratio. We've also got big plans for increasing the flexibility of Prawn's table generation.

Soon, you will be able to create components that consist of elementary drawing operations, images, or whatever you want, and then be able to stick these into table cells just like you would text. These components will also be able to be rendered directly on the PDF document itself, possibly in multiple places. If we do it write, this might permit people to write some custom widgets that could be distributed as plugins to the core, which would be pretty neat.

Long term wise?
I really want to work with the PDF::Writer users to get the necessary features into Prawn to allow them to migrate. The big hurdle here is that we won't be attempting any sort of API compatibility, but our features and stability will hopefully be appealing enough to bring people over to us.  From there, my dream is to retire PDF::Writer and change the Prawn namespace to PDF, yielding PDF::Document.

Once this is done, I want to bring in closer integration with PDF::Reader (currently maintained by James Healy). Though it's likely these projects will remain separate gems, I'd like to unify them under a single overarching Ruby PDF project. From there, we can also bring other PDF related packages into the fold, and then have a truly unified PDF solution for Ruby.

But this all depends on how fast things move, and how open the community is to this idea. Time will tell.

Is life hard for Ruby hackers nowadays?
Why would it be?  We're a demanded commodity, and clients need us more than we need them. Our community is awesome, even under the enormous growing pains Rails has steadily laid onto us.  However, I can't complain about a community that'll happily shell out some cash to let someone they trust hack on projects for them. It shows that even with the commercial successes going on, there are still a lot of people left supporting grassroots efforts, and that is very encouraging.

The main trouble I see is that the internet hype machine has created a lot of drama and skewed public perception so that people tend to think Ruby programmers are zealots who only want to program in Ruby and bash everything else. Speaking generally, this couldn't be farther from the true.  Many great Rubyists are actually even more annoyed by this problem than outsiders are, so I feel the pain of others on this one. ;)

Why do you stop blogging at Oreilly ?
I will be blogging on O'Reilly News. O'Reilly is changing the way their blogging network is structured internally, and there are some big changes in the works that haven't quite been discussed publicly as far as I'm aware. But I'll still be on O'Reilly talking about Ruby, only the URL is changing. The standards for content on O'Reilly News will be a little different but I like the way things are headed over there.

For my informal technical posts, I'm starting up a blog that is separate from my personal blog to help keep things a bit more focused. Those interested in that sort of thing can follow me once I've got the customized blogging software I'm building.

All in all, both places will allow me to dabble into languages and concepts other than Ruby. I often want to write about various *nix tools I'm using, and I've been meaning to dabble into Erlang a bit more, so it'll let me do some more varied posting, which I think will be more fun.

Rate this Article

Adoption
Style

BT