Changes

Jump to navigation Jump to search
7,789 bytes added ,  14:08, 17 January 2015
m
add links to new pages
{{todo|Beware, this doesn’t fit the current export files and ePub workflow as of January 2015!}} < [[Epub]]| [[XML]] | [[Export]] | [[ePub|New ePub docs]]>
Creating an ebook with ConTeXt is still tedious and needs a lot of manual work - that will not change, since everyone has other needs, uses different structures etc.
Here I’ll show you my workflow for creating ebooks of my songbooklets (that use [[LilyPond]] via [http[modules://modules.contextgarden.net/t-filter |filter module]] for the notes).
I’m using ConTeXt’s [[Project structure]], separating content in products (for me: single booklets) and components (for me: single songs) with a common stylesheet (environment).
Unfortunately, ConTeXt has a bug in XML creation in this setup.
Beware, you need a current beta version of ConTeXt, since Hans fixed some export related bugs in the last few days! --[[User:Hraban|Hraban]] 27 August 13 September 2014.
== ConTeXt setup ==
<texcode>
\setupexport[ hyphen=yes,
%firstpage={cover.jpg}, % is ignored
title={Songbook},
\settaggedmetadata[
% here you can set as many metadata entries as you like
%firstpage={cover.jpg}, % is ignored
title={Songbook},
name=ebook, % this becomes the name of the output directory
author={Hraban},
subtitle={}, version={\expandexpanded\currentdate}] % doesn’t work]
\setupinteraction[state=start,
color=,contrastcolor=,
subtitle={},
keywords={},
author={Hraban}] \definehighlight[emph][style=italic] % use \emph{something} instead of {\em something}
</texcode>
Make sure to tag all your structural elements with {{cmd|start...}}-{{cmd|stop...}}, e.g. {{cmd|startchapter}}, but even {{cmd|startparagraph}}!
 
In places where {{cmd|startparagraph}} does not work, such as itemizations, where it causes a blank line after the bullet and before the item text, use {{cmd|bpar}} (and closing {{cmd|epar}}) to tag paragraphs.
Then you can call ConTeXt and its ePub script:
We’ll mostly work with "export.xml" that contains all your content (check that, you’ll miss everything that was not properly tagged).
== Fix export.xml ePub structure == This is the directory structure that we need for our ePub:
If you run the epub script on a single file, you’ll get a well<pre>/songbook.tree/├── META-formed and usable exportINF│   └── container.xml├── OEBPS│   ├── Fonts│   │   └── somefont.otf│   ├── Images│   │   ├── ...│   │   ├── c_farewell-1.png│   │   ├── c_farewell-2.png│   │   ├── c_farewell.png│   │   ├── ...│   │   └── cover.jpg│   ├── Styles│   │   └── style.css│   ├── Text│   │   ├── _intro.html│   │   ├── aut_1.html│   │   ├── ...│   │   └── aut_99. If you use a project structure, the root node {{code|&lt;document&gt;}} is missinghtml│   ├── cover. Just put it in manually (after the comment lines)html│   ├── songbook. You can also move the {{code|&lt;metadata&gt;}} block out of the first structure, but that’s merely a cosmetical erroropf│   └── toc.ncx└── mimetype</pre>
A proper We use mimetype and container.xml unchanged from ConTeXt’s epub script and (re)create everything else.At the end this structure is just zipped with an "epub" file ending. == Unchanged files == For the records: === {{code|mimetype}} === <pre>application/epub+zip</pre> === {{code|exportcontainer.xml}} starts like this:===
<xmlcode>
&lt;<?xml version="1.0" encoding="UTF-8" standalone="yes" ?&gt; &lt;!-- input filename : solo -->&lt;!-- processing date : Wed Aug 27 13:47:46 2014 -->&lt;!-- context <container version : 2014.08="1.21 09:56 -->&lt;!-- exporter version : 0.31 --> &lt;document language="en" filexmlns="solo" date="Wed Aug 27 13urn:oasis:names:47tc:46 2014" context="2014.08.21 09opendocument:56" version="0.31" xmlns:m=container"http://www.w3.org/1998/Math/MathML"&gt;> <metadatarootfiles> <metavariable namerootfile full-path="authorOEBPS/songbook.opf" media-type="application/oebps-package+xml">Hraban</metavariable> </metadatarootfiles> <section detail="chapter" location="aut:1"/container>...
</xmlcode>
 
You don’t need the attributes of the document node, even if we could use the language setting.
== Transform XML to HTML ==
I installed Saxon on my Mac with MacPorts, then instead of just "saxon" you must call {{code|java -jar /opt/local/share/java/saxon9he.jar}}.
This is my === {{code|export2html.xsl}}:===
<xmlcode>
/>
<xsl:variable name="within-paragraph">0</xsl:variable ><!-- statusxsl: are we variable name="within a paragraph? -section">0</xsl:variable ><xsl:variable name="previous-section">0</xsl:variable >
<xsl:template match='section'><!-- <xsl:if test="@detail='part'"> <xsl:text disable-output-escaping="yes"><![CDATA[</div></body></html>]]></xsl:text> </xsl:if>--> <xsl:result-document method="xml" href="aut_{@implicit}.html"> <htmlxmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title><xsl:value-of select='.//metavariable[@name="title"]sectiontitle'/> </title> <xsl:for-each select="//metavariable"> <meta> <xsl:attribute name="name"> <xsl:value-of select="@name"/> </xsl:attribute> <xsl:attribute name="content"> <xsl:apply-templates/> </xsl:attribute> </meta> </xsl:for-each> <link rel="stylesheet" href="../Styles/style.css" type="text/css" ></link> </head> <body> <xsl:attributename="lang"> <xsl:value-of select='//document/@language'/> </xsl:attribute > <!-- <xsl:variable name="contentprevious-section">{$within-section}</xsl:variable > <xsl:variable name="within-section">{@detail}</xsl:variable > -->
<xsl:apply-templates/>
</xsl:attribute> </meta> </xsl:for-each> <link rel="stylesheet" href="style.css" type="text/css" ></link> <!-- for testing the html outside the ePub tree --> <link rel="stylesheet" href="Styles/style.css" type="text/css" ></link></head><body lang="de"> <h1 class="booktitle"> <xsl:value-of select='//metavariable[@variable name="titlewithin-section"]'/>{$previous-section}</h1xsl:variable > <h2 class="subtitle"> <xsl:value-of select='//metavariable[@variable name="subtitleprevious-section"]'/>0</h2> <p class="author"><xsl:value-of select='//metavariable[@name="author"]'/></pvariable > <xsl:apply --templates/> </body> </html> </xsl:template> <xsl:template match="metadata"result-document></xsl:template>
<xsl:template match="section">
<a name="{translate(@location,':','_')}"/>
<div class="{@detail}">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="sectiontitle">
<xsl:choose>
<xsl:when test="../@detail='part'">
<h2h1><xsl:apply-templates/> </h2h1>
</xsl:when>
<xsl:when test="../@detail='chapter'">
<h3h2><xsl:apply-templates/></h2> </xsl:when> <xsl:when test="../@detail='Titel'"> <h2><xsl:apply-templates/></h2> </xsl:when> <xsl:when test="../@detail='TitelKlein'"> <h2><xsl:apply-templates/></h3h2>
</xsl:when>
<xsl:when test="../@detail='section'">
<h4h3><xsl:apply-templates/> </h4h3>
</xsl:when>
<xsl:when test="../@detail='subsection'">
<h5h4><xsl:apply-templates/> </h5h4>
</xsl:when>
<xsl:otherwise>
<h6 class="../@detail"><xsl:apply-templates/> </h6>
</xsl:otherwise>
</xsl:choose>
<xsl:template match="delimited">
<span class="delim-{@detail}"><xsl:apply-templates/></span>
</xsl:template>
 
<xsl:template match="construct">
<div class="struct-{@detail}"><xsl:apply-templates/></div>
</xsl:template>
<!-- all the images in my songbook are notes generated by LilyPond via t-filter; in ePub I shorten the file names -->
 
<xsl:template match="image">
<img src="../Images/{substring-after(@name,'prd_songbookprd_hraban-temp-lilypond-')}.png" id="{@id}" alt="{@name}" />
</xsl:template>
<xsl:template match="link">
<a href="#{@location}" title="{@destination}"><xsl:apply-templates/></a></xsl:template> <xsl:template match="register"></xsl:template> <xsl:template match="registerentry"></xsl:template> <xsl:template match="registerpage">
</xsl:template>
 
</xsl:stylesheet>
<!--
h1 = book title
h2 = part title
h3 = chapter
h4 = section
h5 = subsection
-->
</xmlcode>
=== {{code|style.css}} === Now you have a (hopefully usable) (X)HTML file, you need a {{code|style.css}} CSS for the styling.
A simple example:
}
.part { page-break-before: always;} Titel, .chapter {
margin-top: 1em;
border-top: 1px solid #ccc600a00;
}
.lilypond img {
width: 100%;
margin-bottom: 0.25em;
}
</pre>
Create a {{code|cover.xhtml}}:
 
=== {{code|export2cover.xsl}} ===
<xmlcode>
== Create OPF ==
This The [http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm OPF file ] keeps the others together, it lists all resources of the ebook. You will have to adapt the listing of images (since I use only PDFs converted to PNG) and add fonts manually, if you ship any. === {{code|export2opf.xsl}} ===
<xmlcode>
<xsl:template match="/">
<package version="2.0" xmlns="http://www.idpf.org/2007/opf" unique-identifier="BookId">
<!-- see http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm -->
 
<identifier id="1"><xsl:value-of select='//metavariable[@name="identifier"]'/></identifier>
<identifier id="isbn" scheme="isbn"><xsl:value-of select='//metavariable[@name="isbn"]'/></identifier>
<title><xsl:value-of select='//metavariable[@name="title"]'/></title>
<creator><xsl:value-of select='//metavariable[@name="author"]'/></creator>
<subject><xsl:value-of select='//metavariable[@name="subject"]'/></subject>
<description><xsl:value-of select='//metavariable[@name="description"]'/></description>
<publisher><xsl:value-of select='//metavariable[@name="publisher"]'/></publisher>
<language><xsl:value-of select='//document/@language'/></language>
<rights><xsl:value-of select='//metavariable[@name="rights"]'/></rights>
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:title><xsl:value-of select='//metavariable[@name="title"]'/></dc:title>
<dc:language><xsl:value-of select='//document/@language'/></dc:language>
<dc:identifier id="BookId" opf:scheme="UUID">urn:uuid:xxxx3bbe3f04-4275-841f-44d7-7d3a4e0794a5</dc:identifier>
<dc:creator><xsl:value-of select='//metavariable[@name="author"]'/></dc:creator>
<dc:date><xsl:value-of select='//document/@date'/></dc:date>
<meta name="cover" content="cover-html" />
</metadata>
<manifest>
<item id="cover-xhtmlhtml" href="cover.xhtmlhtml" media-type="application/xhtml+xml"/>
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
<item id="contentstyle" href="Styles/style.css" media-type="text/css"/> <item id="intro-xhtmlhtml" href="contentText/_intro.html" media-type="application/xhtml+xml" /> <xsl:for-each select='//section'> <item media-type="application/xhtml+xml"> <xsl:attribute name="id">aut_<xsl:value-of select="@implicit"/>-html</xsl:attribute> <xsl:attribute name="href">Text/aut_<xsl:value-of select="@implicit"/>.html</xsl:attribute> </item> </xsl:for-each> <item media-type="image/jpeg" id="cover" href="Images/cover.jpg"/> <!-- again, LilyPond related images --> <xsl:for-each select='//image'> <item media-type="image/png" id="{@id}"> <xsl:attribute name="href">Images/<xsl:value-of select="substring-after(@name,'prd_hraban-temp-lilypond-')"/>.png</xsl:attribute> </item> </xsl:for-each> <!-- add fonts manually --> <!-- <item media-type="application/x-font-otf" id="" href="Fonts/xyz.otf" /> <item media-type="application/x-font-ttf" id="" href="Fonts/xyz.ttf" /> -->
</manifest>
<spine toc="ncx">
<itemref idref="cover-xhtmlhtml" /> <itemref idref="contentintro-xhtmlhtml" /> <xsl:for-each select='//section'> <itemref> <xsl:attribute name="idref">aut_<xsl:value-of select="@implicit"/>-html</xsl:attribute> </itemref> </xsl:for-each>
</spine>
This one will probably differ from your setup – I (ab)use an index for an alphabetically ordered table of contents.
The structure that ConTeXt outputs for index entries is somewhat uncomfortable...
 
=== {{code|export2ncx.xsl}} ===
<xmlcode>
<meta name="dtb:uid" content="BookId" />
<meta name="dtb:depth" content="1" />
<meta name="dtb:totalPgeCount" > <xsl:attribute name=" content"> <xsl:value-of select='count(section[starts-with(@detail,"0Titel" )])' /> </xsl:attribute> </meta> <meta name="dtb:maxPageNumber"> <xsl:attribute name=" content"> <xsl:value-of select='count(section[starts-with(@detail,"0Titel" )])' /> </xsl:attribute> </meta>
</head>
<navMap>
<navPoint id="aut_0" origin="aut_0" playOrder="0"> <navLabel> <text>Cover</text> </navLabel> <content src="cover.html"/> </navPoint> <navPoint id="aut_1" origin="aut_1" playOrder="1">
<navLabel>
<text>Start</text>
</navLabel>
<content src="contentText/_intro.xhtmlhtml"/>
</navPoint>
<xsl:for-each select="//registerentry">
<navPoint> <xsl:attribute variable name="idlocation"> <xsl:value-of select='translate((following-sibling./descendant::registerpages/registerpage/link/@location)[1], '/> </xsl:variable > <xsl:variable name="origin"> <xsl:"value-of select='//registerlocation[@internal=$location]/ancestor::section[starts-with(@detail, "_Titel")]/@implicit'/> </xsl:variable >  <navPoint> <xsl:attributename="id"> <xsl:value-of select='$location'/> </xsl:attribute> <xsl:attribute name="origin"><xsl:value-of select="$origin" /></xsl:attribute> <xsl:attribute name="playOrder"> <xsl:value-of select="2 + count(preceding-sibling::registerentry)" /> </xsl:attribute> <navLabel> <text><xsl:applyvalue-templatesof select='./registercontent'/></text> </navLabel> <content> <xsl:attribute name="src">content.xhtml#Text/aut_<xsl:value-of select='translate((following-sibling::registerpages/registerpage/link/@location)[1], ":", "_")$origin'/>.html</xsl:attribute> </content> </navPoint>
</xsl:for-each>
</xsl:stylesheet>
 
</xmlcode>
The links to a named anchor should work, but don’t in my reader. I must investigate further...
 
== Converting images ==
 
In my case, all images are note lines, generated by LilyPond in one temporary directory. Your mileage will vary.
ConTeXt’s epub script creates a list of images in {{code|export-images.css}}, you might want to parse that to find all images.
 
<pre>
cd $LILYPONDTEMPDIR
for IMG in prd_songbook-temp-lilypond-*.pdf; do
NEWIMG=${IMG#prd_songbook-temp-lilypond-}
convert -density 196 $IMG'[0]' -trim +repage ../songbook.tree/OEBPS/Images/${NEWIMG%.pdf}.png
done
</pre>
 
== Create ePub ==
 
Look at the tree above - are all your files in the right location? Then zip your tree!
 
<pre>
cd songbook.tree
zip -uqr ../songbook.epub *
</pre>
 
Now test it with your reader or editor (e.g. Calibre). (Apple iBooks or Adobe Digital Editions don’t work.)
 
== Shell script ==
 
Of course I don’t do all these steps above manually. Here’s my little shell script.
 
=== {{code|epub.sh}} ===
 
<pre>
#!/bin/bash
# call as "./epub.sh productname"
 
# ConTeXt is not in my usual path (setuptex needs too long to be called with every shell);
# probably your installation is at a different location
if [ "$TEXROOT" == "" ]; then
source ~/Library/texmf/tex/setuptex ~/Library/texmf/tex
fi
 
# all my products are named like "prd_something.tex"
PRD=$1
if [ ! -e prd_${PRD}.tex ]; then
echo "Product ${PRD} not found!"
exit 1
fi
 
# all XSL files are in this WORKDIR
WORKDIR=epub-workflow
 
# my ConTeXt wrapper "makeit.sh" script creates PDFs with a date
ISODATE=`date +"%Y-%m-%d"`
PRDPDF=${PRD}_${ISODATE}.pdf
 
# LilyPond is run in this TEMPDIR and creates its note images there
TEMPDIR=lilytemp
 
EPUBPREFIX=epub_
TREE=${PRD}.tree
OEBPS=${TREE}/OEBPS
SAXON="java -jar /opt/local/share/java/saxon9he.jar"
# http://saxonica.com/documentation/html/using-xsl/commandline.html
 
if [ ! -f export.xml ]; then
echo "File export.xml not found! Trying to run ConTeXt..."
# you should replace this call with your own
./makeit.sh ${PRD}
exit 2
fi
 
if [ ! -f $PRDPDF ]; then
echo Product $PRDPDF not found!
echo Please run "makeit.sh $PRD"
exit 3
fi
 
if [ ! -d $OEBPS ]; then
echo Directory $OEBPS missing!
echo Creating new ePub ...
mtxrun --script epub --make ${PRD}
fi
 
if [ -d $OEBPS ]; then
echo "Creating directories (might exist) ..."
mkdir $OEBPS/Styles
mkdir $OEBPS/Images
mkdir $OEBPS/Fonts
mkdir $OEBPS/Text
 
echo Creating HTML ...
$SAXON -o:$OEBPS/Text/_intro.html -s:export.xml -xsl:$WORKDIR/export2html.xsl
echo Creating OPF ...
$SAXON -o:$OEBPS/${PRD}.opf -s:export.xml -xsl:$WORKDIR/export2opf.xsl
echo Creating ToC NCX ...
$SAXON -o:$OEBPS/toc.ncx -s:export.xml -xsl:$WORKDIR/export2ncx.xsl
echo Creating Cover ...
$SAXON -o:$OEBPS/cover.html -s:export.xml -xsl:$WORKDIR/export2cover.xsl
echo Creating cover image from first page of PDF ...
convert -density 196 $PRDPDF'[0]' +repage $OEBPS/Images/cover.jpg
echo Copying files ...
cp style.css $OEBPS/Styles/
# This copies only fonts from your project directory; adapt.
cp *.?tf $OEBPS/Fonts/
 
echo Converting images from PDF to PNG ...
cd $TEMPDIR
for IMG in prd_${PRD}-temp-lilypond-*.pdf; do
NEWIMG=../$OEBPS/Images/${IMG#prd_${PRD}-temp-lilypond-}
NEWIMG=${NEWIMG%.pdf}.png
if [ ! -f $NEWIMG ]; then
convert -density 196 $IMG'[0]' -trim +repage ${NEWIMG}
fi
done
cd ..
# delete old epub
rm $TREE/${PRD}.epub
rm ${EPUBPREFIX}${PRD}.epub
echo Creating ePub ${EPUBPREFIX}${PRD}.epub ...
cd $TREE
zip -uqr ../${EPUBPREFIX}${PRD}.epub *
cd ..
fi
echo Ready.
</pre>

Navigation menu