Skip to content

Commit

Permalink
Allow custom cell_fill_mode in tables (py-pdf#1117)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas-C committed Mar 1, 2024
1 parent b7e9b11 commit 7e1efc2
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 6 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
## [2.7.9] - Not released yet
### Added
* support for overriding paragraph direction on bidirectional text
* new optional `li_prefix_color` parameter for `FPDF.write_html()`
* support for `start` & `type` attributes of `<ol>` tags, and `type` attribute of `<ul>` tags, when using `FPDF.write_html()`
* new optional `li_prefix_color` parameter for [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html)
* support for `start` & `type` attributes of `<ol>` tags, and `type` attribute of `<ul>` tags, when using [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html)
* [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html) now accepts a `tag_styles` parameter to control the font, color & size of HTML elements: `<a>`, `<blockquote>`, `<li>`...
* [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html) now accepts a `tag_indents` parameter to control, for example, the indent of `<blockquote>` elements
* allow to define custom `cell_fill_mode` logic for tables: [_Set cells background_ - documentation section](https://py-pdf.github.io/fpdf2/Tables.html#set-cells-background). Also added 2 new values: `TableCellFillMode.EVEN_ROWS` & `TableCellFillMode.EVEN_COLUMNS`: [documentation](https://py-pdf.github.io/fpdf2/fpdf/enums.html#fpdf.enums.TableCellFillMode)
### Changed
* improved the performance of `FPDF.start_section()` - _cf._ [issue #1092](https://github.com/py-pdf/fpdf2/issues/1092)
### Deprecated
Expand Down Expand Up @@ -52,7 +53,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
* outer table borders are now drawn continuously for nonzero `gutter_width`/`gutter_height`, with spacing applied inside the border similar to HTML tables - thanks to @mjasperse - cf. [#1071](https://github.com/py-pdf/fpdf2/issues/1071)
* removed the requirement that all rows in a `Table` have the same number of columns - thanks to @mjasperse
### Deprecated
- font aliases (`Arial``Helvetica`, `CourierNew``Courer`, `TimesNewRoman``Times`). They will be removed in a later release.
- font aliases (`Arial``Helvetica`, `CourierNew``Courier`, `TimesNewRoman``Times`). They will be removed in a later release.

## [2.7.7] - 2023-12-10
### Added
Expand Down
2 changes: 2 additions & 0 deletions docs/HTML.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ pdf.output("html.pdf")

## Styling HTML tags globally

_New in [:octicons-tag-24: 2.7.9](https://github.com/py-pdf/fpdf2/blob/master/CHANGELOG.md)_

The style of several HTML tags (`<a>`, `<blockquote>`, `<code>`, `<pre>`, `<h1>`, `<h2>`, `<h3>`...) can be set globally, for the whole HTML document, by passing `tag_styles` to `FPDF.write_html()`:

```python
Expand Down
13 changes: 13 additions & 0 deletions docs/Tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,19 @@ The cell color is set following those settings, ordered by priority:
4. The table setting `cell_fill_color`, if `cell_fill_mode` indicates to fill a cell
5. The document `.fill_color` set before rendering the table

Finally, it is possible to define your own cell-filling logic:

```python
class EvenOddCellFillMode():
@staticmethod
def should_fill_cell(i, j):
return i % 2 and j % 2

...
with pdf.table(cell_fill_color=lightblue, cell_fill_mode=EvenOddCellFillMode()) as table:
...
```


## Set borders layout

Expand Down
23 changes: 20 additions & 3 deletions fpdf/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def coerce(cls, value):

raise ValueError(f"{value} is not a valid {cls.__name__}")

raise TypeError(f"{value} cannot convert to a {cls.__name__}")
raise TypeError(f"{value} cannot be converted to a {cls.__name__}")


class CoerciveIntEnum(IntEnum):
Expand Down Expand Up @@ -317,15 +317,32 @@ class TableCellFillMode(CoerciveEnum):
COLUMNS = intern("COLUMNS")
"Fill only table cells in odd columns"

EVEN_ROWS = intern("EVEN_ROWS")
"Fill only table cells in even rows"

EVEN_COLUMNS = intern("EVEN_COLUMNS")
"Fill only table cells in even columns"

@classmethod
def coerce(cls, value):
"Any class that has a .should_fill_cell() method is considered a valid 'TableCellFillMode' (duck-typing)"
if callable(getattr(value, "should_fill_cell", None)):
return value
return super().coerce(value)

def should_fill_cell(self, i, j):
if self is self.NONE:
return False
if self is self.ALL:
return True
if self is self.ROWS:
return bool(i % 2)
return i % 2 == 1
if self is self.COLUMNS:
return bool(j % 2)
return j % 2 == 1
if self is self.EVEN_ROWS:
return i % 2 == 0
if self is self.EVEN_COLUMNS:
return j % 2 == 0
raise NotImplementedError


Expand Down
Binary file added test/table/table_cell_fill_mode.pdf
Binary file not shown.
Binary file added test/table/table_with_cell_fill_custom_class.pdf
Binary file not shown.
43 changes: 43 additions & 0 deletions test/table/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from fpdf import FPDF, FPDFException
from fpdf.drawing import DeviceRGB
from fpdf.fonts import FontFace
from fpdf.table import TableCellFillMode

from test.conftest import assert_pdf_equal, LOREM_IPSUM


Expand Down Expand Up @@ -267,6 +269,27 @@ def test_table_with_cell_fill(tmp_path):
assert_pdf_equal(pdf, HERE / "table_with_cell_fill.pdf", tmp_path)


class EvenOddCellFillMode:
@staticmethod
def should_fill_cell(i, j):
return i % 2 and j % 2


def test_table_with_cell_fill_custom_class(tmp_path):
pdf = FPDF()
pdf.add_page()
pdf.set_font("Times", size=16)
lightblue = (173, 216, 230)
with pdf.table(
cell_fill_color=lightblue, cell_fill_mode=EvenOddCellFillMode()
) as table:
for data_row in TABLE_DATA:
row = table.row()
for datum in data_row:
row.cell(datum)
assert_pdf_equal(pdf, HERE / "table_with_cell_fill_custom_class.pdf", tmp_path)


def test_table_with_internal_layout(tmp_path):
pdf = FPDF()
pdf.add_page()
Expand Down Expand Up @@ -732,3 +755,23 @@ def test_table_with_varying_col_count(tmp_path):
table.row(subset)

assert_pdf_equal(pdf, HERE / "table_with_varying_col_count.pdf", tmp_path)


def test_table_cell_fill_mode(tmp_path):
pdf = FPDF()
pdf.add_page()
pdf.set_font("Helvetica")
light_sky_blue = (150, 200, 255)
headings_style = FontFace(fill_color=128) # grey
for mode in ("ROWS", "COLUMNS", "EVEN_ROWS", "EVEN_COLUMNS"):
pdf.cell(text=f"cell_fill_mode=TableCellFillMode.{mode}:")
pdf.ln(10)
with pdf.table(
TABLE_DATA,
headings_style=headings_style,
cell_fill_mode=getattr(TableCellFillMode, mode),
cell_fill_color=light_sky_blue,
):
pass
pdf.ln()
assert_pdf_equal(pdf, HERE / "table_cell_fill_mode.pdf", tmp_path)

0 comments on commit 7e1efc2

Please sign in to comment.