Add basic support for adding SVG pictures to docx files #1343 #1386
Add basic support for adding SVG pictures to docx files #1343 #1386takis wants to merge 0 commit intopython-openxml:masterfrom
Conversation
|
Hello, Is there a target date for this code to be committed to the master ? I really need this implementation. Thanks for the awesome software. |
|
Hi @marcuoli, No, unfortunately not. I do try to keep my fork in sync with the main repository. |
|
I hope this patch will be merged soon. I'm trying to use your patch, but it doesn't appear to work with matplotlib figures since their sizes are in Example: import docx
from docx.shared import Inches
import numpy as np
import matplotlib.pyplot as plt
from io import BytesIO
from tempfile import mktemp
x = np.linspace(-2*np.pi, 2*np.pi, 100)
fig, ax = plt.subplots()
ax.plot(x, np.sin(x), color="C0")
ax.plot(x, np.cos(x), color="C1")
buf = BytesIO()
fig.savefig(buf, format="svg")
w, h = (Inches(s) for s in fig.get_size_inches())
p = mktemp(suffix=".svg")
fig.savefig(p)
# doesn't work
doc = docx.Document()
doc.add_picture(buf, w, h)Traceback: I think a pt is 1.33x a pixel in svgs. If so, it might be easy to at least handle pt. But maybe it depends on dpi? |
|
With this patch I can insert mpl figures. It's written rather verbose, as I don't really know the style of From 458df2e57c57be410e6d2486ae67e44cebbd177e Mon Sep 17 00:00:00 2001
From: Rasmus <git@pank.eu>
Date: Fri, 18 Oct 2024 10:02:49 +0200
Subject: [PATCH] svg: Handle non-pixels units
---
src/docx/image/svg.py | 32 ++++++++++++++++++++++++++++----
1 file changed, 28 insertions(+), 4 deletions(-)
diff --git a/src/docx/image/svg.py b/src/docx/image/svg.py
index 0247a77..4be43e1 100644
--- a/src/docx/image/svg.py
+++ b/src/docx/image/svg.py
@@ -33,13 +33,37 @@ class Svg(BaseImageHeader):
"""
return "svg"
+ @classmethod
+ def _dimension_to_px(cls, s):
+ """Convert SVG unit *s* to pixels.
+
+ Based on the `table`_ on absolute length in W3 CSS Values 3.
+
+ .. table: https://www.w3.org/TR/css-values-3/#absolute-lengths
+ """
+ s = str(s)
+ unit = s.lstrip("0123456789.").casefold()
+ snumber = s[:-len(unit)] if len(unit) > 0 else s
+ number = float(snumber)
+ inch = 96
+ cm = inch/2.54
+ units = {"cm": cm,
+ "mm": cm/10,
+ "q": cm/40, # 'Q' in W3 table
+ "in": inch,
+ "pc": inch/6,
+ "pt": inch/72,
+ "px": 1}
+ # Unitless is pixels
+ number_px = number * units.get(unit, 1)
+ return int(number_px)
+
@classmethod
def _dimensions_from_stream(cls, stream):
stream.seek(0)
data = stream.read()
root = ET.fromstring(data)
- # FIXME: The width could be expressed as '4cm'
- # See https://www.w3.org/TR/SVG11/struct.html#NewDocument
- width = int(root.attrib["width"])
- height = int(root.attrib["height"])
+ # The width could be expressed as '4cm'
+ width = cls._dimension_to_px(root.attrib["width"])
+ height = cls._dimension_to_px(root.attrib["height"])
return width, height
--
2.44.0.windows.1
``` |
There was a problem hiding this comment.
This PR broke a unitest which need to add xmlns:asvg="http://schemas.microsoft.com/office/drawing/2016/SVG/main
to
tests/test_files/snippets/inline.txt.
some of svg files without "width" and "height" not supported yet.
eg:
<svg viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Icons_CheckboxCrossed" overflow="hidden"><path d="M37.076 62.948 48.008 52.201 58.939 62.948 63.146 58.67 52.286 47.994 63.146 37.318 58.939 33.04 48.008 43.787 37.076 33.04 32.87 37.318 43.729 47.994 32.87 58.67 37.076 62.948Z"/><path d="M21 21 21 75 75 75 75 21ZM69 69 27 69 27 27 69 27Z"/></svg>
I have fixed them and added some unittests in my private fork
Original svg images used |
|
@sgtyfianalisisfinanciero AI've written an package that hotpatches python-docx to support svgs based on this thread that I use for work until svg support is merged. Would that be interesting for others? |
|
@pank nervermind, the problem was not with the images or the mpl code that generated it. Trying to elaborate a minimal reproducible example I catched the issue My workflow was something like that:
Removing the saving step solves the issue. I'm clueless about why, but it's fine On the other hand I think your hotfix package would be very interesting for a lot of people. While this get merged, everyone who needed that feature could just |
|
How it goes? |
|
@sgtyfianalisisfinanciero sorry about the delay. I wanted to add tests and read through the code, but didn't manage before my going on vacation. I still haven't managed, but have added the hotpatch package here: https://github.com/pank/python-docx-svg I haven't added it to PyPi, but could do so if that would be useful. It can still be installed via |
|
And more news on this? It seems like the patch has addressed the issue, but is still waiting to be merged? |
See issues #351, #651, #659.
This replaces both earlier pull requests: