Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rotate text for table header #1140

Open
Tomnl opened this issue Mar 27, 2024 · 5 comments
Open

Rotate text for table header #1140

Tomnl opened this issue Mar 27, 2024 · 5 comments

Comments

@Tomnl
Copy link

Tomnl commented Mar 27, 2024

Please explain your intent
I would like to rotate text for a table header. In particular, have the heading text rotated so that it vertical in the table.

As far as I can tell this not currently possible.

Describe the solution you'd like
When using the pdf.table functionality as described in the docs, it would be great if there was a way to rotate the text in the cells (particulary for the table header).

Wishful thinking... but perhaps defined something like this

with pdf.table() as table:
    headings = table.row()
    headings.cell("Long heading name 1", rotate=90)
    headings.cell("Long heading name 2", rotate=90)
    headings.cell("Age")
    headings.cell("City")

I have looked into using the pdf.rotation approach described here but it does not seem compatible with pdf.table

e.g. the following row.cell will not be changed by the pdf.rotation (and would be difficult to know the x and y coordinates to use anyway)

with pdf.table() as table:
    row = table.row()
    with pdf.rotation(angle=90, x=10, y=300):
        row.cell(text='Long heading name 1') 

Additional context
See below for example format (not produced by fpdf2) to clarify the format I am referring to.

Untitled
ref

@Lucas-C
Copy link
Member

Lucas-C commented Mar 27, 2024

Hi @Tomnl

Thank you for reaching out and suggesting this feature.

I think it could be a handy addition.
Would you like to work on adding this feature to fpdf2 yourself?

Regarding how this feature would operate, I'm not sure that pdf.rotation() would be the best choice.
Maybe an optional rotate=<number> parameter passed to Row.cell() or Table.row() would be better.

In order to build the final table-related feature, a first "building-block" would be to be able to render some text block (with FPDF.write(), FPDF.text(), FPDF.cell() or FPDF.multi_cell()) at a given (X, Y) top-left corner position, with a given rotation applied to text. We will especially need that in FPDF.multi_cell(), so that when .multi_cell(..., output=MethodReturnValue.PAGE_BREAK | MethodReturnValue.HEIGHT) is called in Table._render_table_cell(), we can retrieve the cell height.

Also, we actually have too few unit tests regarding the rotation of text content, i.e. combining FPDF.rotation() with FPDF.write(), FPDF.text(), FPDF.cell() & FPDF.multi_cell().
Any addition of tests regarding those cases would be welcome!

@Tomnl
Copy link
Author

Tomnl commented Mar 27, 2024

Thanks for the quick reply @Lucas-C.

Maybe an optional rotate= parameter passed to Row.cell() or Table.row() would be better.

I agree that seems to be the logical place to add it

In order to build the final table-related feature, a first "building-block" would be to be able to render some text block (with FPDF.write(), FPDF.text(), FPDF.cell() or FPDF.multi_cell()) at a given (X, Y) top-left corner position, with a given rotation applied to text. We will especially need that in FPDF.multi_cell(), so that when .multi_cell(..., output=MethodReturnValue.PAGE_BREAK | MethodReturnValue.HEIGHT) is called in Table._render_table_cell(), we can retrieve the cell height.

So am I correct in thinking that within the .multi_cell() (and more generally FPDF.write(), FPDF.text(), FPDF.cell()) there should be an option to rotate the text and output the correct height? Would that still be using FPDF.rotation() or a new function?

Also, we actually have too few unit tests regarding the rotation of text content, i.e. combining FPDF.rotation() with FPDF.write(), FPDF.text(), FPDF.cell() & FPDF.multi_cell().

Not sure how much help I can bring. But maybe I can contribute a unit test first to help me understand the code base a bit better and then see what I could contribute!

@Lucas-C
Copy link
Member

Lucas-C commented Mar 27, 2024

So am I correct in thinking that within the .multi_cell() (and more generally FPDF.write(), FPDF.text(), FPDF.cell()) there should be an option to rotate the text and output the correct height?

Yes, I think that could be handy.
I'd be curious to know @gmischler opinion on that.

Would that still be using FPDF.rotation() or a new function?

Yes, that would be the simplest way to implement it, and I do not see any issue with using this approach.

Not sure how much help I can bring. But maybe I can contribute a unit test first to help me understand the code base a bit better and then see what I could contribute!

That would be very welcome! 🙂
You can start by reading this page: https://py-pdf.github.io/fpdf2/Development.html

@gmischler
Copy link
Collaborator

There's quite a few challenges here.

First, there's the general question of supporting vertically arranged text, which may or may not get handled by the same code.
There are at least two methods to do this. One group of scripts (eg. chinese and japanese) keep the orientation of the individual glyphs, and just stack them on top of each other. In those cases (not sure if there are exceptions) both writing directions are possible.
grafik
Another group (eg. Mongolian) are actually written horizontally, and the software then needs to rotate the result 90° clockwise. Displaying the text in horizontal orientation is typographically wrong, but common in mixed language text.
grafik

The other general question is, if we want to support other rotation angles than 90 degrees. Spreadsheet software usually allows rotating the text in a cell within a wide gamut.

grafik
LibreOffice supports the full 360°, but rotates wrapped text as a block, lifting some lines above the baseline.

grafik
Excel can only support +/- 90° of rotation, but it staggers wrapped line of text to follow the baseline. (It also sometimes gets confused about which border lines to draw, but that's besides the point here.)

And the third general question: Where do we want to support the rotation of text.
The original suggestion here was in table headers, which implies table cells in general. And since table cells are soon going to be reimplemented as text regions, it's probably a good idea to start there. And once we're looking at that, should whole regions support vertical and/or rotated text, or does it make more sense to add this functionality to individual paragraphs?

Besides the general questions, there's also quite a few details to consider.

line wrapping angled text

  • as block
  • staggered
    With our current table code, creating slanted cell outlines as the spreadsheets do is definitively not trivial. Maybe someone will eventually come up with an idea for that anyway...

Width and height determination:

  • conventionally: width fixed, height variable
  • vertical text: height fixed, width variable?
  • angled text: how to limit extents? May need both width and height fixed (for rectangular outlines).

Now obvously, this isn't a catalog of what sould get implemented right now. I just tried to collect as many of the poential features we might want to consider. The goal is, if you implement something, try to do so in a way that doesn't stand in the way of other features later.
I'm perfectly fine if you only want to consider horizontal and vertical text within orthogonal shapes for now. text regions will offer tools to fill text into other types of shape, which may lend a hand in allowing it to be at any arbitrary angle.

I'm sure there are other aspects that I can't think of right now...

@Lucas-C
Copy link
Member

Lucas-C commented Apr 30, 2024

Now obvously, this isn't a catalog of what sould get implemented right now. I just tried to collect as many of the poential features we might want to consider. The goal is, if you implement something, try to do so in a way that doesn't stand in the way of other features later.
I'm perfectly fine if you only want to consider horizontal and vertical text within orthogonal shapes for now. text regions will offer tools to fill text into other types of shape, which may lend a hand in allowing it to be at any arbitrary angle.

I fully agree: we can start with a basic (limited) implementation for now, but keep in mind how it could be generalized later on 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants