Sourced from fpdf2's releases.
Add resource access controls, SVG complexity limits, Optional Content Groups, and other features and bug fixes
[2.8.8] - 2026-08-09
[!WARNING] Upgrading to fpdf2 2.8.8 is strongly recommended for applications that render user-provided images, SVGs, or HTML content.
Added
- Punjabi (pa) tutorial translation - thanks to
@Pawansingh3889FPDF.svg_limitsandSVGLimitsto configure SVG complexity limits while rendering SVG imagesresource_access_policyand Security considerations documentationFPDF.optional_content()context manager to mark content as visible on screen only or in print only, using PDF Optional Content Groups - cf. [issue #441](py-pdf/fpdf2#441), based on a recipe by@digidigital- thanks to@eugen-goebel- basic support for SVG
<symbol>elements in the SVG parser - thanks to@Theo1335- basic support for SVG
<switch>elements in the SVG parser - cf. [issue #537](py-pdf/fpdf2#537) - thanks to@dannymaaz- support for keeping aspect ratio for images in templates - cf. [issue #1118](py-pdf/fpdf2#1118) - thanks to
@prateek-dagarFixed
- custom height passed to
Paragraph.ln()in a text region is now applied to the line it terminates instead of the first line of the following paragraph - cf. [issue #1786](py-pdf/fpdf2#1786) - thanks to@Sanjays2402- the optional
numpyimport inimage_parsing.pyno longer crashes on CPUs unsupported by numpy'smanylinuxwheel baseline;RuntimeErroris now treated the same asImportError, sonumpydegrades to unavailable instead of taking downimport fpdf- cf. [issue #1908](py-pdf/fpdf2#1908) - thanks to@stumpylog- font state (family, style, size, current font, and the page-level "font is set" flag) no longer leaks back onto the
FPDFinstance after atext_columns()/text_region()context exits, so a subsequentpdf.cell()/pdf.write()renders at the caller's font instead of the last paragraph's - cf. [issue #1804](py-pdf/fpdf2#1804) - thanks to@Pawansingh3889- text rendering when the first text on a page starts with a fallback glyph - cf. [issue #1772](py-pdf/fpdf2#1772)
- preserve boundary-neutral formatting during bidirectional text preprocessing - cf. [issue #1779](py-pdf/fpdf2#1779)
- transform application on user space gradients - cf. [issue #1784](py-pdf/fpdf2#1784)
- dependency extras for camelot-py and endesive on pyproject.toml - cf. [issue #1792](py-pdf/fpdf2#1792)
- preserve link annotations during dry-run of
FPDF.multi_cell- cf. [issue #1807](py-pdf/fpdf2#1807) - thanks to@CoLa5- preserve two consecutive markdown links (without space inbetween) - cf. [issue #1814](py-pdf/fpdf2#1814) - thanks to
@CoLa5- support markdown style around markdown links - cf. [issue #1826](py-pdf/fpdf2#1826) - thanks to
@CoLa5- Reset gstate for ToC-rendering - cf. [issue #1837](py-pdf/fpdf2#1837) - thanks to
@CoLa5- preserve markdown format in
FPDF.multi_cellin dry-run - cf. [issue #1840](py-pdf/fpdf2#1840) - thanks to@CoLa5- fix page order after dry-run of
FPDF.multi_cellin ToC - cf. [issue #1836](py-pdf/fpdf2#1836) - thanks to@CoLa5- rendering SVG arcs with very small sweeps that previously rounded to zero - cf. [issue #1831](py-pdf/fpdf2#1831)
- spurious "Not enough horizontal space to render a single character" error when text without break opportunities is split into many small fragments, e.g. by a fallback font alternating with the main font - cf. [issue #1250](py-pdf/fpdf2#1250) - thanks to
@uttam12331- number of surviving escape characters - cf. [issue #1215](py-pdf/fpdf2#1215) - thanks to
@amidou-naba- leading spaces on new lines inside
<pre>and<pre><code>blocks are no longer dropped - cf. [issue #1063](py-pdf/fpdf2#1063) - thanks to@eugen-goebelFPDF.set_font()can restorecurrent_fontwhen the selected font state diverged - cf. [PR #1872](py-pdf/fpdf2#1872) - thanks to@gaoflow- embed CID-keyed CFF fonts as raw CFF programs so browser PDF viewers render them correctly - cf. [issue #1874](py-pdf/fpdf2#1874)
- fixed broken links on documentation not directly leading to the API reference - cf. [issue #1876](py-pdf/fpdf2#1876) - thanks to
@iamfazakb- reject SVG
<use>cycles and excessive nested expansion to prevent resource exhaustion inFPDF.image()- count SVG
<switch>elements in SVG complexity limits- declare the default base state and display order for Optional Content Groups so PDF viewers can list layers correctly - cf. [issue #1895](py-pdf/fpdf2#1895)
Changed
- skip byte-for-byte compressed data comparison when zlib-ng is detected, regardless of OS
Sourced from fpdf2's changelog.
[2.8.8] - 2026-08-09
Added
- Punjabi (pa) tutorial translation - thanks to
@Pawansingh3889FPDF.svg_limitsandSVGLimitsto configure SVG complexity limits while rendering SVG imagesresource_access_policyand Security considerations documentationFPDF.optional_content()context manager to mark content as visible on screen only or in print only, using PDF Optional Content Groups - cf. [issue #441](py-pdf/fpdf2#441), based on a recipe by@digidigital- thanks to@eugen-goebel- basic support for SVG
<symbol>elements in the SVG parser - thanks to@Theo1335- basic support for SVG
<switch>elements in the SVG parser - cf. [issue #537](py-pdf/fpdf2#537) - thanks to@dannymaaz- support for keeping aspect ratio for images in templates - cf. [issue #1118](py-pdf/fpdf2#1118) - thanks to
@prateek-dagarFixed
- custom height passed to
Paragraph.ln()in a text region is now applied to the line it terminates instead of the first line of the following paragraph - cf. [issue #1786](py-pdf/fpdf2#1786) - thanks to@Sanjays2402- the optional
numpyimport inimage_parsing.pyno longer crashes on CPUs unsupported by numpy'smanylinuxwheel baseline;RuntimeErroris now treated the same asImportError, sonumpydegrades to unavailable instead of taking downimport fpdf- cf. [issue #1908](py-pdf/fpdf2#1908) - thanks to@stumpylog- font state (family, style, size, current font, and the page-level "font is set" flag) no longer leaks back onto the
FPDFinstance after atext_columns()/text_region()context exits, so a subsequentpdf.cell()/pdf.write()renders at the caller's font instead of the last paragraph's - cf. [issue #1804](py-pdf/fpdf2#1804) - thanks to@Pawansingh3889- text rendering when the first text on a page starts with a fallback glyph - cf. [issue #1772](py-pdf/fpdf2#1772)
- preserve boundary-neutral formatting during bidirectional text preprocessing - cf. [issue #1779](py-pdf/fpdf2#1779)
- transform application on user space gradients - cf. [issue #1784](py-pdf/fpdf2#1784)
- dependency extras for camelot-py and endesive on pyproject.toml - cf. [issue #1792](py-pdf/fpdf2#1792)
- preserve link annotations during dry-run of
FPDF.multi_cell- cf. [issue #1807](py-pdf/fpdf2#1807) - thanks to@CoLa5- preserve two consecutive markdown links (without space inbetween) - cf. [issue #1814](py-pdf/fpdf2#1814) - thanks to
@CoLa5- support markdown style around markdown links - cf. [issue #1826](py-pdf/fpdf2#1826) - thanks to
@CoLa5- Reset gstate for ToC-rendering - cf. [issue #1837](py-pdf/fpdf2#1837) - thanks to
@CoLa5- preserve markdown format in
FPDF.multi_cellin dry-run - cf. [issue #1840](py-pdf/fpdf2#1840) - thanks to@CoLa5- fix page order after dry-run of
FPDF.multi_cellin ToC - cf. [issue #1836](py-pdf/fpdf2#1836) - thanks to@CoLa5- rendering SVG arcs with very small sweeps that previously rounded to zero - cf. [issue #1831](py-pdf/fpdf2#1831)
- spurious "Not enough horizontal space to render a single character" error when text without break opportunities is split into many small fragments, e.g. by a fallback font alternating with the main font - cf. [issue #1250](py-pdf/fpdf2#1250) - thanks to
@uttam12331- number of surviving escape characters - cf. [issue #1215](py-pdf/fpdf2#1215) - thanks to
@amidou-naba- leading spaces on new lines inside
<pre>and<pre><code>blocks are no longer dropped - cf. [issue #1063](py-pdf/fpdf2#1063) - thanks to@eugen-goebelFPDF.set_font()can restorecurrent_fontwhen the selected font state diverged - cf. [PR #1872](py-pdf/fpdf2#1872) - thanks to@gaoflow- embed CID-keyed CFF fonts as raw CFF programs so browser PDF viewers render them correctly - cf. [issue #1874](py-pdf/fpdf2#1874)
- fixed broken links on documentation not directly leading to the API reference - cf. [issue #1876](py-pdf/fpdf2#1876) - thanks to
@iamfazakb- reject SVG
<use>cycles and excessive nested expansion to prevent resource exhaustion inFPDF.image()- count SVG
<switch>elements in SVG complexity limits- declare the default base state and display order for Optional Content Groups so PDF viewers can list layers correctly - cf. [issue #1895](py-pdf/fpdf2#1895)
Changed
- skip byte-for-byte compressed data comparison when zlib-ng is detected, regardless of OS
e1fc653
release v2.8.8 (#1916)42ec664
add Sanjays2402 as a contributor for code (#1915)af9d7dc
fix(text_region): apply Paragraph.ln(h) height to the line it terminates
(#1904)81951f8
add stumpylog as a contributor for bug, and code (#1913)b30c38c
Fix: catch RuntimeError alongside ImportError for the optional numpy
import (...63df0d0
Update github/codeql-action action to v4.37.6 (#1910)11a30e6
Update crate-ci/typos action to v1.49.0 (#1911)f65707b
Update step-security/harden-runner action to v2.20.1 (#1912)a7f7c89
Update github/codeql-action action to v4.37.4 (#1907)fe9d8f5
Update pypa/gh-action-pypi-publish action to v1.14.2 (#1906)