Transforming plain text to SVG for EPUB 3
The guiding principle of the SEED.html app's data handling is that plain text source content, stored inside the EPUB file, is transformed at authoring time to its xhtml representation.
The previous blog post provides an overview of how this works for chapter-level content for various formats including markdown, textile and org mode.
This post looks at other plain text formats that can be transformed into SVG and included as inline images within the chapter content.
Code blocks and DOM transforms
The SEED.html app provides a text processing pipeline hook called that will be called after the initial transformation of plain text and before the chapter xhtml is written to a file.
The javascript function signature looks like this;
function transformDOM(document, idref)
The first argument is the dom that results from the plain text transform. The
second argument is the manifest item idref for the current chapter. Providing
the idref argument allows dom processing to be different per
chapter.
This means that if the plain text format provides a way of delimiting a block
of plain text (like a blockquote or a
pre code block) the transformDom operation can
further process that text into some other kind of content, for instance an SVG
image.
An example makes this clear.
ABC notation
Here's a block of markdown that includes a code block delimited
by triple back-ticks, with a language type of abc specified after
the opening delimiter.
## Simple scale
```abc
L:1/4
K:C
V: 1 treble-8
CDEF|GABc |]
w: do re mi fa so la ti do
```
You can read all about abc notation at abcnotation.com. I won't cover it further here.
The markdown processing results in a dom which includes the equivalent of this html fragment;
<h2>Simple scale</h2>
<pre>
<code class="language-abc">
L:1/4
K:C
V: 1 treble-8
CDEF|GABc |]
w: do re mi fa so la ti do
</code>
</pre>
This is the document argument that gets passed into
transformDom(document, idref).
So then a suitable implementation of transformDom() might pull
the text content from that code block and do something with it, like pass it
to the abc2svg renderer like this;
document.querySelectorAll('.language-abc').forEach(el => {
const renderOptions = { /* removed for brevity */ };
const abc = new abc2svg.Abc(renderOptions);
abc.tosvg("A song", el.textContent);
});
There's a bunch of additional code not shown that is needed to set up the abc
rendering using the abc2svg library, but in summary it's possible
to swap the pre code element out of the dom and replace it with
the rendered svg image. Here's what the resulting chapter xhtml looks like
with the inline SVG element.
<h2>Simple scale</h2>
<div>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="currentColor" stroke-width=".7"
class="f102 tune0" viewBox="0 0 794 102">
<g class="g" transform="scale(1.33)">
<g transform="translate(0.0, 47.0)">
<path class="slW" d="m0 0h231.5m-231.5 -6h231.5m-231.5 -6h231.5m-231.5 -6h231.5m-231.5 -6h231.5"/>
</g>
<path class="stroke" stroke-width="1" d="M32.7 53.0m-6.11 0h12.22"/>
<path class="bW" d="M127.1 47.0v-24.0M225.5 47.0v-24.0"/>
<path class="bthW" d="M230.0 47.0v-24.0"/>
<text x="4.0,10.0,29.0,53.7,78.4,103.1,135.1,159.8,184.5,209.2"
y="41.0,63.0,53.0,50.0,47.0,44.0,41.0,38.0,35.0,32.0"></text>
<path class="sW" d="M36.2 53.0v-21.0M60.9 50.0v-21.0M85.6 47.0v-21.0M110.3 44.0v-21.0M142.3 41.0v-21.0M167.0 38.0v-21.0M191.7 35.0v-21.0M209.4 32.0v21.0"/>
<g transform="translate(0,47.0)">
<text class="f99" x="26.3" y="24.1">do</text>
<text class="f99" x="52.4" y="24.1">re</text>
<text class="f99" x="75.3" y="24.1">mi</text>
<text class="f99" x="101.8" y="24.1">fa</text>
<text class="f99" x="133.1" y="24.1">so</text>
<text class="f99" x="158.9" y="24.1">la</text>
<text class="f99" x="184.6" y="24.1">ti</text>
<text class="f99" x="206.5" y="24.1">do</text>
</g>
</g>
</svg>
</div>
When rendered in an EPUB reading system that looks like this (but is an SVG not a bitmap image);
End Result
This leaves us with plain text chapter content in markdown format with plain text musical notation in abc format that renders to high-quality SVG in an EPUB book.
Further reading
A previous post includes an EPUB preview which explains abc notation a bit more.
Another post describes a refinement of this approach to enable multiple renderings with the aim of being responsive to device configuration.