How about per-column font-size customization for tables?

52 views
Skip to first unread message

Kazuyoshi Tlacaelel

unread,
Nov 17, 2009, 5:40:45 PM11/17/09
to Prawn
Hi, I've been working with the pdf library and it is great!

Recently I've been working on some PDF-Generation and would like to
add a feature:
different font-sizes to table-columns in a similar way that we can add
different column-widths.

This will take a hash and override only the default or given font-
size.
am a bit skeptical here. Am unsure if I should make it

:font_size => { ... }

or leave the :font_size setting alone and simply add

:font_size => 10, :font_sizes => { 5 => 10, 6 => 8 } # keys are
columns & values are font-sizes

these are the table-options

I wrote something that is more like a sketch, and before forking and
writing those changes
I thought that it would be a good idea to get some feedback.


@@@ sandal said about 7 hours ago:
> Hi. Thanks for sharing this. Maybe you should post to the Prawn mailing list and see what the folks there think?
> I'm open to adding more options to columns, but I also think we're still in the middle of a table overhaul. Brad is the best judge of that.

> Hit up the list and I'll join in the discussion there.

Brett Neumeier

unread,
Nov 19, 2009, 10:09:07 AM11/19/09
to prawn...@googlegroups.com
On Tue, Nov 17, 2009 at 4:40 PM, Kazuyoshi Tlacaelel <kazu...@gmail.com> wrote:
> Recently I've been working on some PDF-Generation and would like to
> add a feature:
> different font-sizes to table-columns in a similar way that we can add
> different column-widths.

Hi Kazuyoshi,

If you are interested, I've just added this feature to
bneumeier/prawn-layout (and sent a pull request, so perhaps it will
show up in the upstream prawn-layout. Look at commit 0fbf4a.

The syntax I used is parallel to :column_widths -- when you create a
table, you can provide a hash that maps column indexes to font sizes,
e.g.:

:column_font_sizes => { 0 => 8, 2 => 12 }

I've also implemented :column_fonts (which allows fonts to be
specified for individual columns in the same way), and :header_font
(which allows a font to be specified for just the header row). Oh, and
:font as an attribute for Cell.

Cheers,

bn

--
Brett Neumeier (bneu...@gmail.com)

Gregory Brown

unread,
Nov 19, 2009, 10:15:13 AM11/19/09
to prawn...@googlegroups.com
On Thu, Nov 19, 2009 at 10:09 AM, Brett Neumeier <bneu...@gmail.com> wrote:
> On Tue, Nov 17, 2009 at 4:40 PM, Kazuyoshi Tlacaelel <kazu...@gmail.com> wrote:

> The syntax I used is parallel to :column_widths -- when you create a
> table, you can provide a hash that maps column indexes to font sizes,
> e.g.:
>
> :column_font_sizes => { 0 => 8, 2 => 12 }

This is one of the problems we're going to need to solve before we
pull anything upstream.
If we keep putting :column_* and :row_* stuff, the API for table is
going to get so bloated, it'll be impossible to remember it all.

But unfortunately I don't yet have an answer here. I sort of think we
should just tear down table and start from the ground up.
Hash based API is failing us here.

But maybe, if we did stick with hashes, I'd want to see

table data, :columns => { :font_sizes => { ... }, :widths => { ... } }


-greg

Brett Neumeier

unread,
Nov 19, 2009, 10:45:28 AM11/19/09
to prawn...@googlegroups.com
On Thu, Nov 19, 2009 at 9:15 AM, Gregory Brown
<gregory...@gmail.com> wrote:
> But unfortunately I don't yet have an answer here.  I sort of think we
> should just tear down table and start from the ground up.
> Hash based API is failing us here.

I am inclined to agree. The way that I think it will probably work
best is to move away from the current scheme of doing absolutely
everything related to table production in the initialization routine
-- I think it would be better to have something more like:

t = pdf.table # optionally pass in some stuff as params here
t.add_row(*array_of_cell_data)
t.add_row(*another_array_of_cell_data)
t.columns[0].font_size = 8
t.columns[1].font = 'Helvetica'
t.headers = *array_of_header_cell_data
t.header_font = 'Times-Roman'
t.columns[2].width = 50
t.rows[1].font_style = :bold
t.borders = :grid
...
...
t.draw

See what I mean? Build things up gradually. Add methods like "columns"
and "rows" that let you access slices of the table. When your table is
fully-defined, render it into the PDF.

One pleasant consequence of this is that you won't have a single
massive rdoc glob that describes absolutely everything about tables or
cells ... since it can be spread out over the entire API.

However! In the meantime, the implementation as it stands is good
enough for me to do my project, so I am not hugely motivated to
implement such a restructuring.

Cheers

Gregory Brown

unread,
Nov 19, 2009, 10:52:08 AM11/19/09
to prawn...@googlegroups.com
On Thu, Nov 19, 2009 at 10:45 AM, Brett Neumeier <bneu...@gmail.com> wrote:
> On Thu, Nov 19, 2009 at 9:15 AM, Gregory Brown
> <gregory...@gmail.com> wrote:
>> But unfortunately I don't yet have an answer here.  I sort of think we
>> should just tear down table and start from the ground up.
>> Hash based API is failing us here.
>
> I am inclined to agree. The way that I think it will probably work
> best is to move away from the current scheme of doing absolutely
> everything related to table production in the initialization routine
> -- I think it would be better to have something more like:
>
> t = pdf.table # optionally pass in some stuff as params here
> t.add_row(*array_of_cell_data)
> t.add_row(*another_array_of_cell_data)
> t.columns[0].font_size = 8
> t.columns[1].font = 'Helvetica'
> t.headers = *array_of_header_cell_data
> t.header_font = 'Times-Roman'
> t.columns[2].width = 50
> t.rows[1].font_style = :bold
> t.borders = :grid


Gah. Now that's starting to look like PDF::SimpleTable.

More thought is needed. I may be chasing a pot of gold in the sky, though.

-greg

Henrik Nyh

unread,
Nov 19, 2009, 12:08:21 PM11/19/09
to prawn...@googlegroups.com
Sent from my iPhone

On 19 nov 2009, at 16.15, Gregory Brown <gregory...@gmail.com>
wrote:
Perhaps

table data, :columns => [{ :width => 123, :font_size => 12 }, …]

Or the same but an indexed hash instead of an array.

Analogous to the Cell shorthand. Could have a Table::Column longhand,
too.

Gregory Brown

unread,
Nov 19, 2009, 12:47:32 PM11/19/09
to prawn...@googlegroups.com
On Thu, Nov 19, 2009 at 12:08 PM, Henrik Nyh <hen...@nyh.se> wrote:
> Sent from my iPhone
>
> On 19 nov 2009, at 16.15, Gregory Brown <gregory...@gmail.com>


>> But maybe, if we did stick with hashes, I'd want to see
>>
>> table data, :columns => { :font_sizes => { ... }, :widths => { ... } }
>
> Perhaps
>
> table data, :columns => [{ :width => 123, :font_size => 12 }, …]
>
> Or the same but an indexed hash instead of an array.

Maybe an improvement on what I have here... but doesn't this really
feel like we're building up an AST?
If so, that's not a good thing :)

-greg

Bryce Mecum

unread,
Nov 19, 2009, 1:27:33 PM11/19/09
to prawn...@googlegroups.com
What about something like:

pdf.table(data) do
# Style your header
rows.first.set({:font_style => :bold, :align => :center})

# Set properties on column 0, 1 and 2
cols[0..2].set({:font_size => 12, :width => 20})

# Style based on condition
cells.select { |cell| cell.text =~ /Yes/ }.set({:text_color => "F00"})

# Bold last row
rows.last.set({:font_style => :bold, :background_color => "CCC"})
end

set(Hash) just contains keys for Cell options.

Gregory Brown

unread,
Nov 19, 2009, 1:33:10 PM11/19/09
to prawn...@googlegroups.com
Ooh, now you're approaching where I wanted to go with this. rather
than set() I might use style() or something more descriptive.
Range support is a great idea.

and we'd probably do the same trick as Prawn::Document in that if you
do table(data) do |t|, you escape the instance_eval trickery.
Also it should be possible (if not pretty) to do everything via the
initializer hash as well. For that, I'd use what Henrik recommended.


table data, :columns => [{ :width => 123, :font_size => 12 }, …]

Okay folks, I think we have a good start here. Thanks for the
feedback. Anyone want to get patching on the existing API to make
this possible? While we may not directly merge it due to the need for
refactoring, a proof of concept would be great!

Kazuyoshi Tlacaelel

unread,
Nov 19, 2009, 9:58:49 PM11/19/09
to prawn...@googlegroups.com


Good, I was wondering were this post went!
I thought I made a mistake while posting it or something.

Yeah, I agree this is a great interface for the end-user.
Even though this will brake BC ( Backwards Compatibility )

Remember you can just pass the hash without quotes
that will make it slightly more readable!

rows.all.style(:font_style => :bold, :align => :center)
rows.all.map { |x| x.style :font_style => :bold }

Just one thing, wasn't ruby 1.9 not allowing parameters
from outside the block?

default_style = { :font_style => :bold, :align => :center }

pdf.table(data) do
rows.all.style(default_style)
end

And yeah, I would like to help refactoring!

- Kazuyoshi Tlacaelel


.
.

--

You received this message because you are subscribed to the Google Groups "Prawn" group.
To post to this group, send email to prawn...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/prawn-ruby?hl=.



Gregory Brown

unread,
Nov 19, 2009, 10:09:22 PM11/19/09
to prawn...@googlegroups.com
On Thu, Nov 19, 2009 at 9:58 PM, Kazuyoshi Tlacaelel <kazu...@gmail.com> wrote:
>
>
> Good, I was wondering were this post went!
> I thought I made a mistake while posting it or something.
> Yeah, I agree this is a great interface for the end-user.
> Even though this will brake BC ( Backwards Compatibility )

Not an issue for us. Prawn explicitly allows for breaking backwards
compatibility on every major release.
This means that 0.5 is not API compatible with 0.6, and 0.7 won't be
compatible with 0.6

While we'll reserve this right even after 1.0, we should have a pretty
well established API by then that won't annoy people with constant
change.
But until then, you've been warned! :)

> Just one thing, wasn't ruby 1.9 not allowing parameters
> from outside the block?

Definitely not, as that'd make them no longer closures :)

You're thinking of shadowed variables.

>> RUBY_VERSION
=> "1.8.6"
>> x = 1
=> 1
>> lambda { |x| x }.call("foo")
=> "foo"
>> x
=> "foo"

>> RUBY_VERSION
=> "1.9.1"
>> x = 1
=> 1
>> lambda { |x| x }.call("foo")
=> "foo"
>> x
=> 1

Thankfully, this is just Ruby 1.9 fixing a borderline buggy behavior,
and has no effect on this API decision.

Kazuyoshi Tlacaelel

unread,
Nov 20, 2009, 1:34:41 AM11/20/09
to prawn...@googlegroups.com


I see, yeah your right about the blocks.
I just ran some tests, I think I misunderstood the docs.

So... is there anyone that has any other ideas regarding this issue or related ideas?
I think, I saw a post talking about vertical text in tables?

or maybe that should be left out of this conversation?

And.. Where is the official issue tracker for prawn?

- Kazuyoshi Tlacaelel
> --
>
> You received this message because you are subscribed to the Google Groups "Prawn" group.
> To post to this group, send email to prawn...@googlegroups.com.
> To unsubscribe from this group, send email to prawn-ruby+...@googlegroups.com.

Gregory Brown

unread,
Nov 20, 2009, 10:33:47 AM11/20/09
to prawn...@googlegroups.com
On Fri, Nov 20, 2009 at 1:34 AM, Kazuyoshi Tlacaelel <kazu...@gmail.com> wrote:
>
>
> I see, yeah your right about the blocks.
> I just ran some tests, I think I misunderstood the docs.
>
> So... is there anyone that has any other ideas regarding this issue or related ideas?
> I think, I saw a post talking about vertical text in tables?
>
> or maybe that should be left out of this conversation?
>
> And.. Where is the official issue tracker for prawn?

prawn-core:

http://github.com/sandal/prawn/issues

prawn-layout (which includes tables):

http://github.com/sandal/prawn-layout/issues

prawn-format:

http://github.com/sandal/prawn-format/issues

Kazuyoshi Tlacaelel

unread,
Nov 24, 2009, 9:06:09 PM11/24/09
to prawn...@googlegroups.com
Sorry for my late reply, I didn't see this email!

Okay, so.. I'll see the issues on the layout and file a issue if it does not exist yet.
Thanks Greg!

vara

unread,
Jan 11, 2010, 11:22:36 PM1/11/10
to Prawn

Hi Brett Neumeier,

can u plz suggest me how to show header row font_size different
from content or body text font_size.
i m using like :column_font_sizes => { 0 => 8,1=.>8, 2 => 8,3 =>8 }
but it is not working

pdf.table data, :position => :center,
:font => :"#{Prawn::BASEDIR}/data/fonts/Chalkboard.ttf",
:font_size => 10,
:header_text_color => "0000CC",
:border_style => :grid,
:column_font_sizes => { 0 => 8,1=.>8, 2 => 8,3
=>8, }
:headers => [ "Room No", "Room Capacity",
"Exam Capacity", "Room Location" ],


Gregory Brown

unread,
Jan 12, 2010, 9:29:50 AM1/12/10
to prawn...@googlegroups.com
On Mon, Jan 11, 2010 at 11:22 PM, vara <var...@gmail.com> wrote:
>
>
> Hi Brett Neumeier,
>
> can u plz suggest me how to

can u plz at least attempt to use full words? I know that we have
many people here for which English is not their first language, and I
want to be sensitive of that, but there isn't any excuse for typing in
the same manner that a 12 year old texts their friends.

-greg

Reply all
Reply to author
Forward
0 new messages