From c7792d6b5a31337740a78c2f0fe07781503c6ff5 Mon Sep 17 00:00:00 2001 From: "Panagiotis H.M. Issaris" Date: Thu, 2 May 2024 13:06:43 +0200 Subject: [PATCH 1/3] Add basic support for adding SVG pictures to docx files See issues #351, #651, #659. --- src/docx/image/__init__.py | 2 ++ src/docx/image/constants.py | 1 + src/docx/image/svg.py | 49 +++++++++++++++++++++++++++++++++++++ src/docx/oxml/__init__.py | 2 ++ src/docx/oxml/ns.py | 1 + src/docx/oxml/shape.py | 45 +++++++++++++++++++++++++++++++--- 6 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 src/docx/image/svg.py diff --git a/src/docx/image/__init__.py b/src/docx/image/__init__.py index d28033ef1..c67cc32a0 100644 --- a/src/docx/image/__init__.py +++ b/src/docx/image/__init__.py @@ -9,6 +9,7 @@ from docx.image.jpeg import Exif, Jfif from docx.image.png import Png from docx.image.tiff import Tiff +from docx.image.svg import Svg SIGNATURES = ( # class, offset, signature_bytes @@ -20,4 +21,5 @@ (Tiff, 0, b"MM\x00*"), # big-endian (Motorola) TIFF (Tiff, 0, b"II*\x00"), # little-endian (Intel) TIFF (Bmp, 0, b"BM"), + (Svg, 0, b"\n" ' \n' " \n" - "" % nsdecls("wp", "a", "pic", "r") + "" % nsdecls("wp", "a", "pic", "r", "asvg") ) @@ -149,14 +150,48 @@ def new(cls, pic_id, filename, rId, cx, cy): """Return a new ```` element populated with the minimal contents required to define a viable picture element, based on the values passed as parameters.""" - pic = parse_xml(cls._pic_xml()) + if filename.endswith(".svg"): + pic = parse_xml(cls._pic_xml_svg()) + pic.blipFill.blip.extLst.ext.svgBlip.embed = rId + else: + pic = parse_xml(cls._pic_xml()) + pic.blipFill.blip.embed = rId pic.nvPicPr.cNvPr.id = pic_id pic.nvPicPr.cNvPr.name = filename - pic.blipFill.blip.embed = rId pic.spPr.cx = cx pic.spPr.cy = cy return pic + @classmethod + def _pic_xml_svg(cls): + return ( + "\n" + " \n" + ' \n' + " \n" + " \n" + " \n" + " \n" + " \n" + ' \n' + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ' \n' + ' \n' + " \n" + ' \n' + " \n" + "" % nsdecls("pic", "a", "r", "asvg") + ) + @classmethod def _pic_xml(cls): return ( @@ -178,7 +213,7 @@ def _pic_xml(cls): " \n" ' \n' " \n" - "" % nsdecls("pic", "a", "r") + "" % nsdecls("pic", "a", "r", "asvg") ) @@ -210,6 +245,7 @@ class CT_PositiveSize2D(BaseOxmlElement): cy: Length = RequiredAttribute( # pyright: ignore[reportAssignmentType] "cy", ST_PositiveCoordinate ) + svgBlip = ZeroOrOne("asvg:svgBlip") class CT_PresetGeometry2D(BaseOxmlElement): @@ -276,6 +312,7 @@ class CT_Transform2D(BaseOxmlElement): off = ZeroOrOne("a:off", successors=("a:ext",)) ext = ZeroOrOne("a:ext", successors=()) + embed = OptionalAttribute("r:embed", ST_RelationshipId) @property def cx(self): From a19b71839ad393c431fe53b4ef6c0becef88b604 Mon Sep 17 00:00:00 2001 From: "Panagiotis H.M. Issaris" Date: Thu, 2 May 2024 13:17:25 +0200 Subject: [PATCH 2/3] Detect all XML files as SVG As SVG files can start with the XML declaration, interpret all XML files as SVG for now. --- src/docx/image/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/docx/image/__init__.py b/src/docx/image/__init__.py index c67cc32a0..86168e342 100644 --- a/src/docx/image/__init__.py +++ b/src/docx/image/__init__.py @@ -22,4 +22,5 @@ (Tiff, 0, b"II*\x00"), # little-endian (Intel) TIFF (Bmp, 0, b"BM"), (Svg, 0, b" Date: Thu, 2 May 2024 13:17:41 +0200 Subject: [PATCH 3/3] Python 2 formatting updates * encoding header is no longer needed * from __future__ imports no longer needed --- src/docx/image/svg.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/docx/image/svg.py b/src/docx/image/svg.py index 2436b8892..0247a7766 100644 --- a/src/docx/image/svg.py +++ b/src/docx/image/svg.py @@ -1,7 +1,3 @@ -# encoding: utf-8 - -from __future__ import absolute_import, division, print_function - import xml.etree.ElementTree as ET from .constants import MIME_TYPE