From AsciiDoc/DocBook to PDF, ePub and mobi - part 2

This time we will look into Docbook/Fop/PDF generation, which is much more complicated than what we did previously with HTML and txt.

This is the second post of the serie devoted to the technical side of self-publishing using AsciiDoc and Docbook. Look here to find the rest of them.

From AsciiDoc to DocBook

Ok, now the real stuff begins. DocBook is the key to book preparation.

My toolchain starts with AsciiDoc to DocBook conversion with asciidoc.py. For Docbook versions which were later converted to PDF and downloadable from website it looked like this:

/home/tomek/bin/asciidoc-8.6.5/asciidoc.py --backend docbook --doctype book --attribute icons --attribute docinfo1 --attribute tabsize=4 --verbose --out-file $TARGET/book.xml $MAIN_FILE

For Docbook version for print an additional attribute: --attribute print was used. In the AsciiDoc source of the book I have some ifdef sections which resulted in minor changes between print version and other versions (see http://www.methods.co.nz/asciidoc/userguide.html#_system_macros).

From DocBook to FO

Having Docbook (xml) file ready it is possible to transform it to other formats.

I use xsltproc to create .fo (FO, Formatting Objects, whatever this means) which are later used to create all PDFs versions (for paper version, for A4 and for USLetter). The difference lies in page/margin sizes and different .xsl customization files.

An example of xsltproc execution is given below (in reality it is a one-liner but I reformatted it for better readability):

xsltproc
  --stringparam page.margin.inner "0.5in"
  --stringparam page.margin.outer "0.87in"
  --stringparam double.sided 1
  --stringparam header.column.widths "1 4 1"
  --stringparam generate.toc "book toc,title,table,figure"
  --param local.l10n.xml document\(\'/home/tomek/docs/testbook/resources/custom-format.xml\'\)
  --stringparam callout.graphics 1
  --stringparam navig.graphics 1
  --stringparam admon.textlabel 0 --stringparam admon.graphics 1
  --stringparam admon.graphics.path /home/tomek/book/book/images/icons/
  --stringparam callout.graphics.path /home/tomek/book/book/images/icons/callouts/
  --stringparam navig.graphics.path /home/tomek/book/book/images/icons/
  --stringparam toc.section.depth 1 --stringparam chunk.section.depth 0
  --stringparam page.width "7.5in" --stringparam page.height "9.25in"
  --output $TARGET/book.fo $RESDIR/custom-docbook-font-11.xsl
$TARGET/book.xml

A lot of parameters here, and I would encourage you to google them up (start here) so you know what is the meaning of each of them. As for the values used (like the "0.5in" margins) I used the "trial and error" approach to find the right values. :) Some tools also helped (e.g. CreateSpace verifier) by warning me when I used some not-valid values.

Now let us have a look at the two files which keep some more configuration options: custom-format.xml and custom-docbook-font-11.xsl (BTW. you can name these files according to your liking)

Please see the inline comments to understand the purpose of these files.

custom-format.xml

<?xml version="1.0"?>
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
  <l:l10n language="en">
    <!-- TOC title so all examples - listings in my case
- are gathered under "List of Listings"
instead of the default "List of Examples" -->
    <l:gentext key="ListofExamples" text="List of Listings"/>

    <!-- Title over each listing (instead of default "Example")
%n is number, %t is title -->
    <l:context name="title">
      <l:template name="example" text="Listing %n. %t"/>
    </l:context>

    <!-- References to Tables, Figures and Listings
this sets how the links will be render, so when I put <<listing_my_listing>>
it will be converted to "Listing 6.2.3" in the final version -->
    <l:context name="xref-number-and-title">
      <l:template name="table" text="Table %n"/>
      <l:template name="figure" text="Figure %n"/>
      <l:template name="example" text="Listing %n"/>
      <l:template name="section" text="Section %n"/>
    </l:context>
  </l:l10n>
</l:i18n>

custom-docbook-font-11.xsl

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
  <xsl:import href="/home/tomek/bin/asciidoc-8.6.5/docbook-xsl/fo.xsl"/>

<!-- oh my, I admit I have no clue what does this whole xsl:template part does...
I can't even tell whether it is required :) -->
  <xsl:template name="header.content">
    <xsl:param name="pageclass" select="''"/>
    <xsl:param name="sequence" select="''"/>
    <xsl:param name="position" select="''"/>
    <xsl:param name="gentext-key" select="''"/>
    <fo:block>
      <!-- sequence can be odd, even, first, blank -->
      <!-- position can be left, center, right -->
      <xsl:choose>
        <xsl:when test="$sequence = 'blank'">
          <!-- nothing -->
        </xsl:when>
        <xsl:when test="$position='left'">
          <!-- Same for odd, even, empty, and blank sequences -->
          <xsl:call-template name="draft.text"/>
        </xsl:when>
        <xsl:when test="($sequence='odd' or $sequence='even') and $position='center'">
          <xsl:apply-templates select="." mode="object.title.markup"/>
        </xsl:when>
        <xsl:when test="$position='center'">
          <!-- nothing for empty and blank sequences -->
        </xsl:when>
        <xsl:when test="$position='right'">
          <!-- Same for odd, even, empty, and blank sequences -->
          <xsl:call-template name="draft.text"/>
        </xsl:when>
        <xsl:when test="$sequence = 'first'">
          <!-- nothing for first pages -->
        </xsl:when>
        <xsl:when test="$sequence = 'blank'">
          <!-- nothing for blank pages -->
        </xsl:when>
      </xsl:choose>
    </fo:block>
  </xsl:template>

<!-- main font changed from 12 to 11 -->
  <xsl:param name="body.font.master">11</xsl:param>
<!-- size of section titles -->
  <!-- 1.2 section -->
  <xsl:attribute-set name="section.title.level1.properties">
    <xsl:attribute name="font-size">
      <xsl:value-of select="$body.font.master * 1.9"/>
      <xsl:text>pt</xsl:text>
    </xsl:attribute>
  </xsl:attribute-set>
  <!-- 1.2.3 section -->
  <xsl:attribute-set name="section.title.level2.properties">
    <xsl:attribute name="font-size">
      <xsl:value-of select="$body.font.master * 1.6"/>
      <xsl:text>pt</xsl:text>
    </xsl:attribute>
  </xsl:attribute-set>
  <!-- 1.2.3.4 section -->
  <xsl:attribute-set name="section.title.level3.properties">
    <xsl:attribute name="font-size">
      <xsl:value-of select="$body.font.master * 1.36"/>
      <xsl:text>pt</xsl:text>
    </xsl:attribute>
  </xsl:attribute-set>
  <xsl:attribute-set name="section.title.level4.properties">
    <xsl:attribute name="font-size">
      <xsl:value-of select="$body.font.master * 1.2"/>
      <xsl:text>pt</xsl:text>
    </xsl:attribute>
  </xsl:attribute-set>
  <xsl:attribute-set name="section.title.level5.properties">
    <xsl:attribute name="font-size">
      <xsl:value-of select="$body.font.master"/>
      <xsl:text>pt</xsl:text>
    </xsl:attribute>
  </xsl:attribute-set>
  <xsl:attribute-set name="section.title.level6.properties">
    <xsl:attribute name="font-size">
      <xsl:value-of select="$body.font.master"/>
      <xsl:text>pt</xsl:text>
    </xsl:attribute>
  </xsl:attribute-set>
</xsl:stylesheet>

From FO to PDF

No gotchas here, simply use fop and voila!

fop -fo $TARGET/book.fo -pdf $TARGET/book_a4.pdf

PDF cover

The PDF which is later used to print the book on paper does not include the cover. It is uploaded separately and then handled by CreateSpace. However for A4 and USLetter versions, which are downloadable from the book's website, I need to add a cover myself. This is done with the following snippet of the .xsl customization files:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
  <xsl:import href="/home/tomek/bin/asciidoc-8.6.5/docbook-xsl/fo.xsl"/>
  <xsl:template name="front.cover">
    <xsl:call-template name="page.sequence">
      <xsl:with-param name="master-reference">my-titlepage</xsl:with-param>
      <xsl:with-param name="content">
        <fo:block text-align="center">
<fo:external-graphic src="url(img/cover/cover_a4.jpg)"
                content-height="297mm"/>
        </fo:block>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:template>
</xsl:stylesheet>

To Be Continued...

That is it for today. We have nice PDFs with covers, and we know how to create them with various page/margin/font sizes. Cool.

Next time we will look into ePub/mobi generation. See ya!

 
 
 
This used to be my blog. I moved to http://tomek.kaczanowscy.pl long time ago.

 
 
 

Please comment using