From 5b786dbd8a4e6ed65c48814ced9c7a5d1cdd657d Mon Sep 17 00:00:00 2001 From: Martin Mahner Date: Sat, 26 Jul 2025 07:12:05 +0200 Subject: [PATCH 1/3] Avoid `svg:` prefix in output by directly using the tag instead of `QName` for SVG namespace handling. Fixes #317 Fixes #353 --- qrcode/image/styles/moduledrawers/svg.py | 3 +- qrcode/tests/regression/__init__.py | 0 qrcode/tests/regression/test_svg_rect.py | 44 ++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 qrcode/tests/regression/__init__.py create mode 100644 qrcode/tests/regression/test_svg_rect.py diff --git a/qrcode/image/styles/moduledrawers/svg.py b/qrcode/image/styles/moduledrawers/svg.py index d09f1991..bb1b468c 100644 --- a/qrcode/image/styles/moduledrawers/svg.py +++ b/qrcode/image/styles/moduledrawers/svg.py @@ -53,7 +53,8 @@ class SvgQRModuleDrawer(BaseSvgQRModuleDrawer): def initialize(self, *args, **kwargs) -> None: super().initialize(*args, **kwargs) - self.tag_qname = ET.QName(self.img._SVG_namespace, self.tag) + # Use tag directly instead of QName with namespace to avoid svg: prefix in output + self.tag_qname = self.tag def drawrect(self, box, is_active: bool): if not is_active: diff --git a/qrcode/tests/regression/__init__.py b/qrcode/tests/regression/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/qrcode/tests/regression/test_svg_rect.py b/qrcode/tests/regression/test_svg_rect.py new file mode 100644 index 00000000..77eda094 --- /dev/null +++ b/qrcode/tests/regression/test_svg_rect.py @@ -0,0 +1,44 @@ +import io + +import pytest + +import qrcode +from qrcode.image import svg +from qrcode.tests.consts import UNICODE_TEXT + + +@pytest.mark.parametrize( + "image_factory", + [ + svg.SvgFillImage, + svg.SvgFragmentImage, + svg.SvgImage, + svg.SvgPathFillImage, + # svg.SvgPathImage, # Result does not contain elements. + + This regression test ensures that rect elements in SVG output are rendered as + without the svg: namespace prefix, which can cause rendering issues in + browsers, when loaded in HTML. + + https://github.com/lincolnloop/python-qrcode/issues/353 + https://github.com/lincolnloop/python-qrcode/issues/317 + """ + # Create a QR code + qr = qrcode.QRCode() + qr.add_data(UNICODE_TEXT) + + img = qr.make_image(image_factory=image_factory) + f = io.BytesIO() + img.save(f) + svg_content = f.getvalue().decode("utf-8") + + # Check that there are no elements in the output + assert " elements in the output + assert " Date: Sat, 26 Jul 2025 07:14:01 +0200 Subject: [PATCH 2/3] Update changes --- CHANGES.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 262b84af..e1edd431 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -38,9 +38,10 @@ WIP - **Added** ``GappedCircleModuleDrawer`` (PIL) to render QR code modules as non-contiguous circles. (BenwestGate in `#373`_) - **Added** ability to execute as a Python module: ``python -m qrcode --output qrcode.png "hello world"`` (stefansjs in `#400`_) - **Removed** the hardcoded 'id' argument from SVG elements. The fixed element ID caused conflicts when embedding multiple QR codes in a single document. (m000 in `#385`_) -- Improved test coveraged (akx in `#315`_) -- Fixed typos in code that used ``embeded`` instead of ``embedded``. For backwards compatibility, the misspelled parameter names are still accepted but now emit deprecation warnings. These deprecated parameter names will be removed in v9.0. (benjnicholls in `#349`_) +- **Fixed** typos in code that used ``embeded`` instead of ``embedded``. For backwards compatibility, the misspelled parameter names are still accepted but now emit deprecation warnings. These deprecated parameter names will be removed in v9.0. (benjnicholls in `#349`_) +- **Fixed** an issue where an `` Date: Sat, 26 Jul 2025 07:23:21 +0200 Subject: [PATCH 3/3] Use tag directly, no need to detour --- qrcode/image/styles/moduledrawers/svg.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qrcode/image/styles/moduledrawers/svg.py b/qrcode/image/styles/moduledrawers/svg.py index bb1b468c..b27f8279 100644 --- a/qrcode/image/styles/moduledrawers/svg.py +++ b/qrcode/image/styles/moduledrawers/svg.py @@ -53,8 +53,6 @@ class SvgQRModuleDrawer(BaseSvgQRModuleDrawer): def initialize(self, *args, **kwargs) -> None: super().initialize(*args, **kwargs) - # Use tag directly instead of QName with namespace to avoid svg: prefix in output - self.tag_qname = self.tag def drawrect(self, box, is_active: bool): if not is_active: @@ -73,7 +71,7 @@ def initialize(self, *args, **kwargs) -> None: def el(self, box): coords = self.coords(box) return ET.Element( - self.tag_qname, + self.tag, x=self.img.units(coords.x0), y=self.img.units(coords.y0), width=self.unit_size, @@ -91,7 +89,7 @@ def initialize(self, *args, **kwargs) -> None: def el(self, box): coords = self.coords(box) return ET.Element( - self.tag_qname, + self.tag, cx=self.img.units(coords.xh), cy=self.img.units(coords.yh), r=self.radius,