Added
- demonstration Jupyter notebook: [tutorial/notebook.ipynb](https://github.com/py-pdf/fpdf2/blob/master/tutorial/notebook.ipynb)
- new [`.default_page_dimensions`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.default_page_dimensions) property on `FPDF` instances
- support for description list (`<dl>`), description titles (`<dt>`), description details (`<dd>`) and code blocks (`<code>`) in `write_html()` - thanks to yk-jp & seanpmulholland
- support for monochromatic images (PIL `image.mode == '1'`) thanks to GerardoAllende
- the 1000+ unit tests suite is now executed under Linux **<ins>and</ins>** Windows, with extra timing & memory usage checks ensuring we control `fpdf2` resource usage
- new translation of the tutorial in [עברית](https://py-pdf.github.io/fpdf2/Tutorial-he.html), thanks to TzviGreenfeld
- new documentation for using [PyPDF2](https://github.com/py-pdf/PyPDF2) with `fpdf2`, added by devdev29: https://py-pdf.github.io/fpdf2/CombineWithPyPDF2.html
- new documentation for using [Jinja](https://jinja.palletsprojects.com/) with `fpdf2`: https://py-pdf.github.io/fpdf2/TemplatingWithJinja.html
Deprecated
- `HTMLMixin` is deprecated, and not needed anymore: **the `write_html()` method is now natively available in the `FPDF` class** - thanks to yk-jp
Removed
- `open()` & `close()` methods, that were only used internally and should never have been called by end-user code
- `FPDF.state`, which was an instance of the `DocumentState` enum, and has been replaced by moving the final rendering logic into a new `fpdf.output` module
Fixed
- after an "empty" `cell()`, `ln()` applied a line height of zero [601](https://github.com/py-pdf/fpdf2/issues/601)
- when using `multi_cell()` with `max_line_height` to render multiline text, the last line is now rendered like all the others
- templates don't leak graphics state changes to their surroundings anymore; [570](https://github.com/py-pdf/fpdf2/issues/570)
- automatic page break is never performed on an empty page (when the Y position is at the top margin)
- fixed [`insert_toc_placeholder()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.insert_toc_placeholder) usage with [`footer()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.footer) and `{{nb}}`; [548](https://github.com/py-pdf/fpdf2/issues/548)
- the SVG parser now accepts `stroke-width` attribute values with an explicit unit, thanks to gmischler; [526](https://github.com/py-pdf/fpdf2/issues/526)
- the SVG parser now accepts absolute units for `width` and `height` attributes, thanks to darioackermann; [555](https://github.com/py-pdf/fpdf2/issues/555)
- `write_html()` method now correctly handles whitespace when parsing HTML. `<pre></pre>` blocks still maintain spaces, tabs and line breaks.
Changed
- the first parameter of `FPDF.add_font()` is now **optional**: if it is not provided, the base name of the `fname` font path is used to define the font family. Hence `pdf.add_font(fname="fonts/NotoSansArabic.ttf")` will define a font named `NotoSansArabic`.
- the output of [`embed_file()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.embed_file) is now a `PDFEmbeddedFile`, not a string, but the internal file name can be retrieved through its `.basename` property
- forbid use of `get_y()` & `local_context()` inside `unbreakable()` as it is currently not supported; [557](https://github.com/py-pdf/fpdf2/discussions/557)
- [fontTools](https://fonttools.readthedocs.io/en/latest/) minimal version requirement set to 4.34.0; [#524](https://github.com/py-pdf/fpdf2/issues/524)