Skip to main content

Extends Markdown with support for inline SVG images.

Project description

Inline SVG Extension for Markdown

A Python-Markdown extension that enables inline embedding of local SVG files directly into rendered HTML. Unlike standard Markdown image syntax—which outputs <img> tags. This extension inserts the actual SVG markup, enabling:

  • full CSS styling of embedded SVGs
  • consistent scaling behaviour
  • figure + figcaption support
  • improved control over accessibility and semantics

Features

Inline SVG injection

Embed SVG files using a syntax similar to normal images:

![caption](path/to/image.svg)

or without caption:

!(path/to/image.svg)

Automatic <figure> + <figcaption> wrapping

If a caption is provided, the output becomes:

<figure>
    <svg> ... </svg>
    <figcaption>Your caption</figcaption>
</figure>

Without a caption, only the SVG element is inserted.

Safe Placeholder Handling

The extension first inserts placeholder tokens, preventing Python-Markdown from escaping the SVG. Placeholders are later replaced with the final SVG markup in the postprocessor phase.

Internal Caching

SVG files are parsed once and stored in a global cache for the lifetime of the process, improving performance.

Installation

pip install markdown isvg

Use the extension:

import markdown
from isvg import InlineSVGExtension

md = markdown.Markdown(extensions=[InlineSVGExtension(root="assets/svg")])
html = md.convert("![Logo](logo.svg)")

Usage

Basic Inline SVG

!(diagram.svg)

Inline SVG with Caption

![Data Flow](images/flow.svg)

Example HTML Output

<figure>
  <svg xmlns="http://www.w3.org/2000/svg" ...> ... </svg>
  <figcaption>Data Flow</figcaption>
</figure>

Configuration

root

Defines the base directory from which SVG paths are resolved. Defaults to "", the current working directory.

InlineSVGExtension(root="/var/www/assets/svg")

A Markdown reference such as:

![icon](ui/menu.svg)

resolves to:

/var/www/assets/svg/ui/menu.svg

remove_prefix

If your Markdown is generated from a web source that prefixes URLs with /, you can remove that prefix:

InlineSVGExtension(remove_prefix="/")
![logo](/images/logo.svg)

Becomes reference to:

images/logo.svg

remove_prefex defaults to "", which means no prefix is removed.

How it Works

  1. Reference detection A lightweight custom parser matches ![caption](file.svg) and !(file.svg).
  2. Structured extraction caption and href sections are parsed using a bracket-aware tokenizer, not regex grouping. This ensures correct handling of nested brackets.
  3. Path rewriting remove_prefix and root are applied.
  4. File validation
    • Must exist
    • Must end in .svg
    • Must not be remote (http/https///)
  5. Caching & XML parsing SVGs are loaded with xml.etree.ElementTree and stored in a module-level cache for reuse.
  6. Placeholder emission A unique stable placeholder token (\x02path\x03) prevents Markdown from interfering with raw XML.
  7. Postprocessing Placeholders are replaced with the final SVG markup after Markdown rendering is complete.

Error Handling

The extension silently ignores:

  • Non-SVG files
  • Remote URLs (http://, https://, //)
  • Missing paths
  • Invalid or malformed SVGs

In such cases, the original Markdown text is left unchanged.

Security Considerations

Inlining SVGs introduces risks if files are not trusted. SVGs can contain:

  • JavaScript
  • External resource references
  • Embedded HTML
  • CSS injections

If processing user-provided content, sanitize SVGs beforehand using tools such as: external SVG sanitizers or whitelist-based filtering.

Testing

This project includes pytest-based unit tests located in the test/ directory.

Run the full suite with:

pytest test

The tests cover:

  • Correct placeholder insertion
  • Proper caption extraction
  • figure + figcaption generation
  • SVG loading and caching behavior
  • Error-handling paths (invalid SVG, missing files, remote URLs)
  • Interactions with other Python-Markdown extensions

If you extend or modify the extension, adding tests in this folder is highly recommended.

Known Limitations

  • A global cache is used, which persists for the lifetime of the process.
  • Relative links inside SVGs are not rewritten.
  • Interactions with other Markdown extensions may affect final output order.

License

This project is licensed under the GNU General Public License v3.0 (GPLv3). You may redistribute and/or modify it under the terms of the GPLv3.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

isvg-1.0.3.tar.gz (18.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

isvg-1.0.3-py3-none-any.whl (17.1 kB view details)

Uploaded Python 3

File details

Details for the file isvg-1.0.3.tar.gz.

File metadata

  • Download URL: isvg-1.0.3.tar.gz
  • Upload date:
  • Size: 18.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.1

File hashes

Hashes for isvg-1.0.3.tar.gz
Algorithm Hash digest
SHA256 f5067c42f06d0ed00a7962face20a596e3322e1955846aaccdb298b01eb1953d
MD5 05fad102bcdc1b9dae6d37abb2046001
BLAKE2b-256 ebec6f38a89fc0f3e379f513fd3e9b5f3a0a820caf1481cd89bcfdcd051d9471

See more details on using hashes here.

File details

Details for the file isvg-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: isvg-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 17.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.1

File hashes

Hashes for isvg-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 8789c33770202720213fd16c960594ff3594c245df0165c6b22c91e0b4600b97
MD5 82ea2532a39601941d1713a7447e1196
BLAKE2b-256 2a16a92f23684af036429a6948d285c290088494f235bb06a2939b93e1cde094

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page