Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
### Fixed
* SVG: `currentColor` and `inherit` are now read regardless of case, like the color keywords, so `fill="currentcolor"`, as in the Font Awesome icons of many web pages, no longer fails with `ValueError: unsupported color specification currentcolor` - thanks to @RavSinghChandan
* SVG: black or gray text no longer fails with an `AssertionError` when it is in a `<tspan>` that has its own style, as in every text written by Inkscape: the check on the text color left out `DeviceGray`, the color fpdf2 uses for black and gray - thanks to @RavSinghChandan
* SVG: an element or group with `display="none"`, set as an attribute, in its `style` or by a CSS class, such as a hidden Inkscape layer, is no longer drawn; an element inside it can still be drawn by a `<use>` - thanks to @RavSinghChandan
* SVG: an image without an `xmlns` declaration no longer fails with `ValueError: substring not found` when it contains a tag that is not supported, such as `<title>` or `<script>`; the tag is skipped with a warning, as in an image that declares the namespace - thanks to @RavSinghChandan
* `FPDF.text()` raises a clear `ValueError` for a NaN or infinite `x` or `y`, like `FPDF.set_xy()`, instead of writing `nan` or `inf` into the page, which is not a valid PDF number - thanks to @RavSinghChandan
* SVG: `clip-path="none"`, as written by Inkscape, no longer fails with an `AssertionError`, and a `url(#id)` reference to a clip path whose id contains a `-` or a `.`, or that is quoted, now finds that clip path, instead of failing with a `KeyError` or clipping with another one whose id is the part before the `-` or `.` - thanks to @RavSinghChandan
Expand Down
5 changes: 5 additions & 0 deletions fpdf/svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -2232,6 +2232,11 @@ def _build_group_child(
inherited_style: dict[str, Any],
) -> None:
"""Convert one graphics child while preserving its parent's style."""
display = _get_attr_or_style(child, "display", self._style_map_for(child))
if display is not None and display.strip().lower() == "none":
# The element and its children are not drawn, as for a hidden Inkscape
# layer. It is still built, so that ids inside it can be referenced.
pdf_group = GraphicsContext()
if child.tag in xmlns_lookup("svg", "defs"):
self.handle_defs(child)
elif child.tag in xmlns_lookup(
Expand Down
39 changes: 39 additions & 0 deletions test/svg/test_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,45 @@ def test_svg_text_gray_color_in_styled_tspan(
svg.draw_to_page(pdf)
assert f"{color_operators} [] 0 d BT" in bytes(pdf.output()).decode("latin-1")

@pytest.mark.parametrize(
"hidden_rect",
[
'<rect width="10" height="10" display="none"/>',
# a hidden Inkscape layer
'<g style="display:none"><rect width="10" height="10"/></g>',
(
"<style>.hidden { display: none }</style>"
'<rect class="hidden" width="10" height="10"/>'
),
],
)
def test_svg_display_none(self, hidden_rect):
svg = fpdf.svg.SVGObject(
'<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">'
f'{hidden_rect}<circle cx="25" cy="25" r="3"/></svg>'
)
pdf = fpdf.FPDF()
pdf.compress = False
pdf.add_page()
svg.draw_to_page(pdf)
output = bytes(pdf.output()).decode("latin-1")
assert " re " not in output # the rectangle
assert " c " in output # the circle

def test_svg_display_none_referenced(self):
"""An element in a hidden group can still be drawn by a <use>."""
svg = fpdf.svg.SVGObject(
'<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">'
'<g display="none"><rect id="square" width="10" height="10"/></g>'
'<use href="#square" x="20"/></svg>'
)
pdf = fpdf.FPDF()
pdf.compress = False
pdf.add_page()
svg.draw_to_page(pdf)
output = bytes(pdf.output()).decode("latin-1")
assert output.count(" re ") == 1

def test_svg_symbol(self):
svg_data = (
'<svg xmlns="http://www.w3.org/2000/svg" '
Expand Down
Loading