Skip to content

Add SVG #351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
mrlarssen opened this issue Jan 21, 2017 · 12 comments
Open

Add SVG #351

mrlarssen opened this issue Jan 21, 2017 · 12 comments
Labels

Comments

@mrlarssen
Copy link

mrlarssen commented Jan 21, 2017

Is it possible to add SVG to the document? For instance an svg-string such as

< svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" version="1.1">
< rect width="200" height="100" stroke="black" stroke-width="6" fill="green" />
</ svg>

would be perfect. Or just a svg file?

@scanny
Copy link
Contributor

scanny commented Jan 21, 2017

Can you do that from the Word application UI?

@mrlarssen
Copy link
Author

@scanny
Copy link
Contributor

scanny commented Jan 22, 2017

I suspect it translates them into Windows Metafile Format (WMF) and stores them that way. You'd need to try it and then inspect the .docx file (it's a zip archive) and see what the image was that got included. I expect the file extension of the image file name would reliably indicate the underlying file type its stored as.

@mrlarssen
Copy link
Author

I guess the documentation is outdated, as this approach does not let me insert an svg into the word document. So I assume the limitation lays with word itself?

Then I need to look into how I can convert svg to png in Python.

Thanks for your response.

@scanny
Copy link
Contributor

scanny commented Jan 23, 2017

This page has some insights on why it might not be working for you:
https://www.quora.com/How-would-you-insert-a-svg-file-in-PowerPoint

It could be your PowerPoint version is not the very latest; I know mine isn't :)

It's still not clear whether the new PowerPoint 2016 supports SVG files natively or whether they are just converted to WMF/EMF and stored that way, like it does with PDF/EPS images.

@ftomassetti
Copy link

A PR related to this is pending #798

@kuri65536
Copy link

kuri65536 commented Aug 11, 2020

Thank you to python-docx, this is very useful software.

I had done to embed svg images with python-docx.

this is a part of my
mkdocs-theme-topdf .
code is here

BTW, I found the PR and this is just a sample workaround for
the current version.

Screenshot_20200811-153340~2

(this preview from Word android)

from docx.image import image

def run(doc: Document):
    monkey()
    para = doc.add_paragraph()
    pic = para.add_run().add_picture("sample.svg")
    compose_asvg(pic)

def compose_asvg(pic: Tag) -> None:
    embed = '{%s}embed' % (
        "http://schemas.openxmlformats.org/officeDocument/2006/relationships")
    url = "http://schemas.microsoft.com/office/drawing/2016/SVG/main"
    url14 = "http://schemas.microsoft.com/office/drawing/2010/main"
    etree.register_namespace("asvg", url)
    etree.register_namespace("a14", url14)

    ablip = pic._inline[-1][-1][-1][1][0]
    elst = OxmlElement('a:extLst')
    ablip.append(elst)
    embed_id = ablip.attrib.get(embed, "")
    del(ablip.attrib[embed])

    aext = OxmlElement('a:ext')
    elst.append(aext)
    aext.set("uri", "{28A0092B-C50C-407E-A947-70E740481C1C}")
    ldpi = etree.Element('{%s}useLocalDpi' % url14)
    aext.append(ldpi)
    ldpi.set("val", "0")

    aext = OxmlElement('a:ext')
    elst.append(aext)
    aext.set("uri", "{96DAC541-7B7A-43D3-8B79-37D633B846F1}")

    asvg = etree.Element('{%s}svgBlip' % url)
    aext.append(asvg)
    asvg.set(embed, embed_id)

def monkey() -> None:
    global default_factory
    if default_factory is not None:
        return
    default_factory = image._ImageHeaderFactory
    image._ImageHeaderFactory = _ImageHeaderFactory

def _ImageHeaderFactory(stream: IO[Text]) -> image.BaseImageHeader:
    stream.seek(0)
    buf = stream.read(32)
    if "<svg".encode("latin") in buf:
        stream.seek(0)
        return Svg.from_stream(stream)
    assert default_factory is not None
    return default_factory(stream)

class Svg(image.BaseImageHeader):
    @classmethod
    def from_stream(cls, stream: IO[Text]) -> '_SvgParser':
        """Return a |Svg| instance having header properties parsed from image
             in *stream*."""
        # this is dummy.
        return cls(100, 100, 96, 96)

    @property
    def content_type(self) -> Text:
        return "image/svg"

@scanny
Copy link
Contributor

scanny commented Aug 11, 2020

Nice, @kuri65536, thanks for posting this :)

@tikuma-lsuhsc
Copy link

tikuma-lsuhsc commented Apr 27, 2021

@kuri65536 - Thanks for the nice workaround!

For anyone else still waiting for the PR, @kuri65536 's code caused a small hiccup in my code. Specifically, _ImageHeaderFactory() is not accounting for valid preceding XML tags. Here is how I fixed it:

  import re

  def _ImageHeaderFactory(stream):
      stream.seek(0)
      buf = stream.read(32).decode("utf-8")
      while re.match(r"\s*\<\?|\s*\<\!", buf):
          m = re.match(r"(?:\s*<[\s\S]*?>\s*)+", buf)
          if m:
              buf = buf[m.end(0) :]
          if not m or len(buf) < 4:
              buf += stream.read(32).decode("utf-8")
      if buf.startswith("<svg"):
          stream.seek(0)
          return Svg.from_stream(stream)
      assert default_factory is not None
      return default_factory(stream)

@cristianocca
Copy link

It's been some time, any news or actual guide how to add an svg image to the docx template file?

@jfthuong
Copy link

If it might help,

Here are 2 Word with a similar image in PNG and SVG that have been added in the same place.

I have also extracted the files and pretty-formatted the XML files for easier comparison

png_vs_svg.zip

@takis
Copy link

takis commented Jun 24, 2022

Hi,

I had a first try at implementing this, but have only tested using simple SVGs. The files open without issues in Word on my Mac Mini.

Any feedback welcome. I haven't written any tests yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants