Skip to content

Commit bb3aaa1

Browse files
authored
Min row height in tables + docs on fpdf2 internals (#1346)
1 parent a3cc423 commit bb3aaa1

21 files changed

+366
-185
lines changed

CHANGELOG.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
1919
## [2.8.3] - Not released yet
2020
### Added
2121
* support for [shading patterns (gradients)](https://py-pdf.github.io/fpdf2/Patterns.html)
22-
* support for strikethrough text
23-
* Improved SVG image speed by 50% to 70% - thanks to @petri-lipponen-movesense - [PR #1350](https://github.com/py-pdf/fpdf2/pull/1350)
22+
* improved SVG image speed by 50% to 70% - thanks to @petri-lipponen-movesense - [PR #1350](https://github.com/py-pdf/fpdf2/pull/1350)
23+
* support for <s>strikethrough text</s>
24+
* support for [setting a minimal row height in tables](https://py-pdf.github.io/fpdf2/Tables.html#setting-row-height)
25+
* support for [`v_align` at the row level in tables](https://py-pdf.github.io/fpdf2/Tables.html#setting-vertical-alignment-of-text-in-cells)
26+
* documentation on [verifying provenance of `fpdf2` releases](https://py-pdf.github.io/fpdf2/#verifying-provenance)
27+
* documentation on [`fpdf2` internals](https://py-pdf.github.io/fpdf2/Internals.html)
2428
### Fixed
2529
* [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html): Fixed rendering of content following `<a>` tags; now correctly resets emphasis style post `</a>` tag: hyperlink styling contained within the tag authority. - [Issue #1311](https://github.com/py-pdf/fpdf2/issues/1311)
2630

docs/Internals.md

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# fpdf2 internals
2+
3+
## FPDF.pages
4+
`FPDF` is designed to add content progressively to the document generated, page by page.
5+
6+
Each page is an entry in the `.pages` attribute of `FPDF` instances.
7+
Indices start at 1 (the first page) and values are [`PDFPage`](https://py-pdf.github.io/fpdf2/fpdf/output.html#fpdf.output.PDFPage) instances.
8+
9+
`PDFPage` instances have a `.contents` attribute that is a [`bytearray`](https://docs.python.org/3/library/stdtypes.html#bytearray) and contains the **Content Stream** for this page
10+
(`bytearray` makes things [a lot faster](https://github.com/reingart/pyfpdf/pull/164)).
11+
12+
Going back to a previously generated page to add content is possible,
13+
using the [`.page` attribute](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.page), but may result in unexpected behavior, because [.add_page()](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.add_page) takes special care to ensure the page's content stream matches `FPDF`'s instance attributes.
14+
15+
16+
## syntax.py & objects serialization
17+
The [syntax.py](https://github.com/py-pdf/fpdf2/blob/master/fpdf/syntax.py) package contains classes representing core elements of the PDF syntax.
18+
19+
Classes inherit from the [PDFObject](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.syntax.PDFObject) class, that has the following properties:
20+
21+
* every PDF object has an `.id`, that is assigned during the document serialization by the [OutputProducer](#outputproducer)
22+
* the `.serialize()` method renders the PDF object as an `obj<</>>endobj` text block. It can be overridden by child classes.
23+
* the `.content_stream()` method must return non empty bytes if the PDF Object has a _content stream_
24+
25+
Other notable core classes are:
26+
27+
* [Name](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.syntax.Name)
28+
* [Raw](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.syntax.Raw)
29+
* [PDFString](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.syntax.PDFString)
30+
* [PDFArray](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.syntax.PDFArray)
31+
* [PDFDate](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.syntax.PDFDate)
32+
33+
34+
## GraphicsStateMixin
35+
This _mixin_ class, inherited by the `FPDF` class,
36+
allows to manage a stack of graphics state variables:
37+
38+
* docstring: [fpdf.graphics_state.GraphicsStateMixin](https://py-pdf.github.io/fpdf2/fpdf/graphics_state.html#fpdf.graphics_state.GraphicsStateMixin)
39+
* source file: [graphics_state.py](https://github.com/py-pdf/fpdf2/blob/master/fpdf/graphics_state.py)
40+
41+
The main methods of this API are:
42+
43+
* [_push_local_stack()](https://py-pdf.github.io/fpdf2/fpdf/graphics_state.html#fpdf.graphics_state.GraphicsStateMixin._push_local_stack): Push a graphics state on the stack
44+
* [_pop_local_stack()](https://py-pdf.github.io/fpdf2/fpdf/graphics_state.html#fpdf.graphics_state.GraphicsStateMixin._pop_local_stack): Pop the last graphics state on the stack
45+
* [_get_current_graphics_state()](https://py-pdf.github.io/fpdf2/fpdf/graphics_state.html#fpdf.graphics_state.GraphicsStateMixin._get_current_graphics_state): Retrieve the current graphics state
46+
* [_is_current_graphics_state_nested()](https://py-pdf.github.io/fpdf2/fpdf/graphics_state.html#fpdf.graphics_state.GraphicsStateMixin._is_current_graphics_state_nested): Indicate if the stack contains items (else it is empty)
47+
48+
Thanks to this _mixin_, we can use the following semantics:
49+
```python
50+
{% include "../tutorial/graphics_state.py" %}
51+
```
52+
53+
The graphics states used in the code above
54+
can be depicted by this diagram:
55+
56+
``` mermaid
57+
stateDiagram-v2
58+
direction LR
59+
state gs0 {
60+
initial1 : Base state
61+
}
62+
state gs1 {
63+
initial2 : Base state
64+
font_size_pt2 : font_size_pt=16
65+
underline2 : underline=True
66+
font_size_pt2 --> initial2
67+
underline2 --> font_size_pt2
68+
}
69+
gs0 --> gs1: Step 1
70+
state "gs0" as stack2 {
71+
initial3 : Base state
72+
}
73+
gs1 --> stack2: Step 2
74+
```
75+
76+
77+
## OutputProducer
78+
In `fpdf2`, the `FPDF` class is used to store the document **definition**,
79+
its state as it is progressively built. Most attributes and internal data is **mutable**.
80+
81+
Once it's done, when the [FPDF.output()](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.output) method is called, the actual PDF file creation is delegated to the [OutputProducer](https://py-pdf.github.io/fpdf2/fpdf/output.html#fpdf.output.OutputProducer) class.
82+
83+
It performs the serialization of the PDF document,
84+
including the generation of the [cross-reference table & file trailer](https://py-pdf.github.io/fpdf2/fpdf/output.html#fpdf.output.PDFXrefAndTrailer).
85+
This class uses the `FPDF` instance as **immutable input**:
86+
it does not perform any modification on it.
87+
88+
<!-- Other topics to mention:
89+
90+
## Vector Graphics
91+
drawing.py & svg.py packages
92+
93+
## Text regions & flow ?
94+
95+
## Text shaping ?
96+
97+
-->

docs/Signing.md

+3
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ allows to add a signature based on arbitrary key & certificates, not necessarily
2525
[examples/pdf-verify.py](https://github.com/m32/endesive/blob/master/examples/pdf-verify.py)
2626
or the [`check_signature()`](https://github.com/py-pdf/fpdf2/blob/master/test/conftest.py#L111) function
2727
used in `fpdf2` unit tests can be good starting points for you, if you want to perform PDF signature control.
28+
29+
If you want to sign **existing** PDF documents,
30+
you should consider using PyHanko: <https://pyhanko.readthedocs.io>.

docs/Tables.md

+19-6
Original file line numberDiff line numberDiff line change
@@ -120,24 +120,37 @@ left and right is supplied then c_margin is ignored.
120120

121121
_New in [:octicons-tag-24: 2.7.6](https://github.com/PyFPDF/fpdf2/blob/master/CHANGELOG.md)_
122122

123-
Can be set globally or per cell.
124-
Works the same way as padding, but with the `v_align` parameter.
125-
123+
Can be set globally, per row or per cell, by passing a string or a [VAlign](https://py-pdf.github.io/fpdf2/fpdf/enums.html#fpdf.enums.VAlign) enum value as `v_align`:
126124
```python
127-
125+
...
128126
with pdf.table(v_align=VAlign.M) as table:
129127
...
130-
row.cell(f"custom v-align", v_align=VAlign.T) # <-- align to top
128+
row.cell(f"custom v-align", v_align="TOP")
131129
```
132130

133131
## Setting row height
134-
132+
First, `line_height` can be provided to set the height of every individual line of text:
135133
```python
136134
...
137135
with pdf.table(line_height=2.5 * pdf.font_size) as table:
138136
...
139137
```
140138

139+
_New in [:octicons-tag-24: 2.8.3](https://github.com/py-pdf/fpdf2/blob/master/CHANGELOG.md)_
140+
141+
Second, a global `min_row_height` can be set,
142+
or configured per row as `min_height`:
143+
```python
144+
...
145+
with pdf.table(min_row_height=30) as table:
146+
row = table.row()
147+
row.cell("A")
148+
row.cell("B")
149+
row = table.row(min_height=50)
150+
row.cell("C")
151+
row.cell("D")
152+
```
153+
141154
## Disable table headings
142155

143156
By default, `fpdf2` considers that the first row of tables contains its headings.

0 commit comments

Comments
 (0)