Changes

Jump to navigation Jump to search
11,364 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. If you png│   │   ├── c_farewell-2.png│   │   ├── c_farewell.png│   │   ├── ...│   │   └── cover.jpg│   ├── Styles│   │   └── style.css│   ├── Text│   │   ├── _intro.html│   │   ├── aut_1.html│   │   ├── ...│   │   └── aut_99.html│   ├── cover.html│   ├── songbook.opf│   └── toc.ncx└── mimetype</pre> We use a project structure, the root node {{code|&lt;document&gt;}} is missingmimetype and container. Just put it in manually xml unchanged from ConTeXt’s epub script and (after re)create everything else.At the comment lines)end this structure is just zipped with an "epub" file ending. You can also move  == Unchanged files == For the records: === {{code|&lt;metadata&gt;mimetype}} block out of the first structure, but that’s merely a cosmetical error.=== <pre>application/epub+zip</pre>
A proper === {{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>
</xmlcode>
If you don’t have a different cover picture, create one from the first page of your PDF (using ImageMagick’s {{code|convert}}): <pre>convert -density 196 songbook.pdf'[0]' +repage cover.jpg</pre> == Create OPF == 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><?xml version="1.0" encoding="UTF-8" ?><xsl:stylesheet version= "2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" encoding="utf-8" indent="yes"/> <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:3bbe3f04-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-html" href="cover.html" media-type="application/xhtml+xml"/> <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/> <item id="style" href="Styles/style.css" media-type="text/css"/> <item id="intro-html" href="Text/_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-html" /> <itemref idref="intro-html" /> <xsl:for-each select='//section'> <itemref> <xsl:attribute name="idref">aut_<xsl:value-of select="@implicit"/>-html</xsl:attribute> </itemref> </xsl:for-each> </spine> </package></xsl:template> </xsl:stylesheet></xmlcode> == Create NCX (table of contents) == 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><?xml version="1.0" encoding="UTF-8" ?><xsl:stylesheet version= "2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" encoding="utf-8" indent="yes"/> <xsl:template match="/"><!--<!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN" "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">--><ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">  <head> <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,"Titel")])' /> </xsl:attribute> </meta> <meta name="dtb:maxPageNumber"> <xsl:attribute name="content"> <xsl:value-of select='count(section[starts-with(@detail,"Titel")])' /> </xsl:attribute> </meta> </head>  <docTitle> <text><xsl:value-of select='//metavariable[@name="title"]'/></text> </docTitle>  <docAuthor> <text><xsl:value-of select='//metavariable[@name="author"]'/></text> </docAuthor>  <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="Text/_intro.html"/> </navPoint> <xsl:for-each select="//registerentry"> <xsl:variable name="location"> <xsl:value-of select='(./descendant::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:attribute name="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:value-of select='./registercontent'/></text> </navLabel> <content> <xsl:attribute name="src">Text/aut_<xsl:value-of select='$origin' />.html</xsl:attribute> </content> </navPoint> </xsl:for-each>  </navMap></ncx></xsl:template> </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 $LILYPONDTEMPDIRfor 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}.pngdone</pre> == Create ePub == Look at the tree above - are all your files in the right location? Then zip your tree! <pre>cd songbook.treezip -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 locationif [ "$TEXROOT" == "" ]; then source ~/Library/texmf/tex/setuptex ~/Library/texmf/texfi # all my products are named like "prd_something.tex"PRD=$1if [ ! -e prd_${PRD}.tex ]; then echo "Product ${PRD} not found!" exit 1fi # all XSL files are in this WORKDIRWORKDIR=epub-workflow # my ConTeXt wrapper "makeit.sh" script creates PDFs with a dateISODATE=`date +"%Y-%m-%d"`PRDPDF=${PRD}_${ISODATE}.pdf # LilyPond is run in this TEMPDIR and creates its note images thereTEMPDIR=lilytemp EPUBPREFIX=epub_TREE=${PRD}.treeOEBPS=${TREE}/OEBPSSAXON="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 2fi if [ ! -f $PRDPDF ]; then echo Product $PRDPDF not found! echo Please run "makeit.sh $PRD" exit 3fi 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 somgbook$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 cover${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 ..fiecho Ready.jpg
</pre>

Navigation menu