Inject Fonts into Web SVGs with sed


Monday, 10th February, 2025 2min #web #bash

So you want to embed an SVG on your website and add this to your HTML:

<object class="page" data="input_svg.svg" type="image/svg+xml"></object>

In my case this is an Affinity Designer SVG export.

But now we realize that the fonts don't work. That's because your pretty SVG doesn't tell the browser where to find these fonts. Usually you can fix this with CSS like this, making sure you actually host the .woff file at the specified location:

@font-face {
    font-family: 'Candara';
    src: url('/vendor/fonts/Candara-Regular.woff')format('woff');
    font-weight: normal;
    font-style: normal;
}

Unfortunately this CSS can't just be included in your HTML document, it has to be part of the SVG itself. This is how the original SVG looks like:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg [...]>
    [...]
</svg>

After the injection we need it to look like this:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg [...]>
    <defs>
        <style type="text/css"><![CDATA[
            @font-face {
                font-family: 'Candara';
                src: url('/vendor/fonts/Candara-Regular.woff')format('woff');
                font-weight: normal;
                font-style: normal;
            }
        ]]></style>
    </defs>

    [...]
</svg>

All Hail sed, a stream editor!

So, how do we do this?

We have the font-loading CSS in the file fonts.css. Our first challenge lies in surrounding this CSS with the required SVG stuff.

Let's do this with sed and start with creating the file fonts_css_template.txt:

<defs>
    <style type="text/css"><![CDATA[
OHtFGivqhAswi
    ]]></style>
</defs>

As you can see the (randomly chosen) string OHtFGivqhAswi needs to be replaced with the CSS.

sed "/OHtFGivqhAswi/e cat fonts.css" fonts_css_template.txt | \
    sed 's/OHtFGivqhAswi//' \
    > final_text_to_include_in_svg.txt
  1. The first sed command reads fonts.css and puts it right before OHtFGivqhAswi;
  2. the second deletes OHtFGivqhAswi. This only works because OHtFGivqhAswi is on its own line.
  3. We pipe the output into final_text_to_include_in_svg.txt. This is what needs to be injected into the SVG.

Commence the Injection

sed -E 's/(<svg [^>]+>)/\1\ncI0WWZKD2UKEj\n/' input_svg.svg | \
    sed "/cI0WWZKD2UKEj/e cat final_text_to_include_in_svg.txt" | \
    sed 's/cI0WWZKD2UKEj//' \
    > output_svg.svg
  1. Our first command finds the opening svg tag and appends the random string cI0WWZKD2UKEj, making sure it is on its own line.
  2. This is followed by exactly what we've done before: prepend what needs to be injected,
  3. replace cI0WWZKD2UKEj and
  4. pipe the output where it is needed.

You don't need that ginormous web framework for simple things—some CSS and sed does the trick just fine. Perhaps, first take a look at what the GNU toolbox offers when solving the next challenge you come across.

The Final Script

#!/bin/bash
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"

FONTS_CSS_TEMPLATE="$DIR/fonts_css_template.txt"
FINAL_TEXT_TO_INCLUDE_IN_SVG="$DIR/final_text_to_include_in_svg.txt"
FONTS_CSS_FILE="$DIR/fonts.css"

echo "converting $1 to $2"

sed "/OHtFGivqhAswi/e cat $FONTS_CSS_FILE" "$FONTS_CSS_TEMPLATE" | \
    sed 's/OHtFGivqhAswi//' \
    > "$FINAL_TEXT_TO_INCLUDE_IN_SVG"

sed -E 's/(<svg [^>]+>)/\1\ncI0WWZKD2UKEj\n/' "$1" | \
    sed "/cI0WWZKD2UKEj/e cat $FINAL_TEXT_TO_INCLUDE_IN_SVG" | \
    sed 's/cI0WWZKD2UKEj//' \
    > "$2"

Save this as load_fonts_in_css.sh, run:

chmod +x ./load_fonts_in_css.sh
./load_fonts_in_css.sh input_svg.svg output_svg.svg

Similar Articles


React without a Framework

3rd January, 2026 5min


Reimplementing my homepage without a framework made me more flexible and independant. I only rely on React, TypeScript and Node.js to generate a static HTML+CSS website. Also, it has been a lot of fun!

reveal.js your Presentation

24th June, 2022 14min


reveal.js is a PowerPoint alternative. With it you programmatically define your presentation via HTML. This article shows how you can use reveal.js for your own presentation.

Guided Missiles in Minecraft

6th June, 2025 10min


I'm having a stab at designing an enitity seeking missile in Minecraft with the mc_missile mod. Or: How I blew up my brother.

Automatic Firmware Generation for Spaceflight Hardware based on Schematics

16th February, 2026 119min


Any satellite's Power Conditioning and Distribution Unit (PCDU) fulfills the same purpose, providing the subsystems with electrical power. However, because each satellite has a unique set of subsystems, differing PCDUs must realize differing power distributions. How do you efficiently develop firmware for such similar hardware? One approach is to group components and their PCB layout into a snippet, e.g., an Analog to Digital Converter (ADC) with supportive components. Each PCDU can reuse the same snippets arranged differently to create different power distributions. While this drastically speeds up the hardware design process, previous works failed at translating this speedup to the firmware development process. We propose the Group Netlist, a novel representation of the logical functions of hardware. This machine-readable file format enables automatic firmware generation while remaining agnostic to both programming-language and schematics editor. The electrical engineer annotates the schematics to produce not just the PCB layout but also the Group Netlist. Contrary to initial expectations, we show that the Group Netlist has uses beyond firmware generation. This includes but is not limited to harness specification and snippet based design analysis. We provide the reference implementation kicad_firmware_generation as a ready-to-use product for different projects even outside space-exploration.

All Articles