E-Books (EPUB & PDF)

Laika puts equal emphasis on the generation of e-books as on website generation.

Like all functionality, e-book generation does not require installation of external tools. The EPUB format is supported by Laika's own Scala implementation, whereas PDF support is partially based on Apache FOP.

The latter is not based on LaTeX like many other PDF renderers, but uses XSL-FO as an interim format. The generation of this interim format happens in Laika's own renderers, only the final transformation step to the binary PDF format is delegated to Apache FOP.

Generating E-Books

If you are using the sbt plugin you can use several of its task for generating e-books:

See sbt Plugin for more details.

When using the library API, the EPUB and PDF renderers can be passed to the Transformer or Renderer APIs:

import cats.effect.IO
import laika.api._
import laika.format._
import laika.io.syntax._

val transformer = Transformer
  .from(Markdown)
  .to(EPUB)
  .using(Markdown.GitHubFlavor)
  .parallel[IO]
  .build

transformer.use {
  _.fromDirectory("src")
   .toFile("hello.epub")
   .transform
}

See Library API for more details on these APIs and ensure you have the necessary dependencies in place - the laika-pdf module for PDF or the laika-io module for EPUB - see Dependencies.

Directory Structure

An e-book generated by Laika is always a single, binary file, even when the input is an entire directory of markup files. But the directory structure will be reflected in the navigation elements inside the e-book.

Markup files from the input directory will form the content of the e-book while static files like images and fonts will be embedded into the output when they are referenced from within one or more markup files.

For EPUB specifically it is important to consider what file size to choose for your content. The directory structure inside the generated EPUB container (which is essentially a glorified ZIP) will mirror exactly the structure of the input directory, apart from the additional metadata files it needs to generate. Therefore it is best to avoid very large markup files as they might slow down the experience in the e-book reader, and instead distribute content over a higher number of smaller input files.

See Document Types for general info about the various types of input files Laika supports, and Supported Document Types in this chapter for additional info specific to EPUB and PDF.

Configuration

The most convenient way to configure aspects like metadata, look & feel and navigation for your e-books is to use the built-in default theme called Helium and its settings.

There is a dedicated Theme Settings chapter, so we'll just link the most relevant aspects that can be configured for e-books from here.

Book Navigation

Laika supports a directory structure with sub-directories of any depth. Markup files from the input directory will form the content of the e-book, linearized in depth-first traversal and using your configured Navigation Order.

Laika will generate navigation elements compatible with e-book readers, as shown in the images below:

PDF Navigation in Preview for Mac:

PDF Navigation

EPUB Navigation in iBooks:

EPUB Navigation

The navigation depth can be configured with the Helium API:

import laika.helium.Helium

Helium.defaults
  .epub.navigationDepth(4)
  .pdf.navigationDepth(4)

The default for EPUB is just 2 levels as some readers like iBooks mess with the hierarchy of navigation items when using more than 2 levels. If you increase this setting make sure you verify it's looking good in the targeted readers.

Note that this affects the navigation structure that will be generated for the navigation tools of the respective EPUB or PDF readers.

You might additionally want to insert a table of content into the page flow, right after the cover image, as this would be the only navigation structure that would be available when printing the document. See Table of Contents how to configure such a structure which can also have a different navigation depth than the tree generated for the readers.

Supported Document Types

You can also place images, fonts and other supported file types into the input directory. Laika will embed these files in the generated EPUB container and/or PDF file.

The supported file types / suffixes are:

For EPUB

For PDF

CSS for EPUB

Since content files for EPUB are standard XHTML files (apart from optional EPUB-specific attributes), you can style your e-books with standard CSS.

The Helium API offers ways to register which CSS files you want to be linked from the EPUB documents or alternatively which directories to scan for CSS files. See Auto-Linking CSS & JS Files for details.

When referencing images or fonts from your CSS files, you can use relative paths, as the directory layout will be retained inside the EPUB container.

JavaScript for EPUB

The scope of support for JavaScript may depend on the target reader, so early testing is recommended when scripting EPUB documents.

The Helium API offers ways to register which JavaScript files you want to be linked from the EPUB documents or alternatively which directories to scan for JavaScript files. See Auto-Linking CSS & JS Files for details.

In case you want to create a custom EPUB template you need to provide some indicator in the config header whether the template needs scripting support, as each scripted document needs a flag in the OPF metadata for the EPUB container. The key for the attribute is laika.epub.scripted and valid values are always, never, auto. The auto value which is also used in Helium's default template sets the flag whenever there are any documents in the input tree with the suffix .epub.js or .shared.js.

CSS for PDF

Laika offers the unusual, but convenient feature of CSS styling for PDF. It allows for customization in a syntax familiar to most users.

The CSS files need to be placed into the root directory of your input tree with a name in the format <name>.fo.css.

However, as PDF is a page-based format and in Laika's case expects XSL-FO as an interim format, there are a few subtle differences:

An example for styling a level-2 header:

Header.level2 {
  font-family: sans-serif;
  font-weight: bold;
  font-size: 14pt;
}

The Header type selector refers to the name of the AST node Laika produces for headers. The level2 class is a style that gets rendered for each header node to be able to style levels differently

Only a few of Laika's nodes get rendered with class attributes. You can examine HTML output to get an overview over rendered attributes as they are largely identical to those rendered for EPUB and PDF.

Likewise, out of the box only a subset of nodes get rendered with an auto-generated id: headers, footnotes or citations.

Customized Output

In cases where styling with CSS alone is not sufficient, there are additional, lower-level hooks to customize the rendered output.

Templates

You can place custom default templates into the root directory of the input tree, named default.template.epub.xhtml for EPUB and default.template.fo for PDF.

For EPUB the template will be applied to each rendered file individually, for PDF the generated XSL-FO will first be concatenated and then the template will be applied to the single final FO document.

Customizing the PDF template would require knowledge of XSL-FO, but is hopefully rarely ever necessary as PDFs can be styled by Laika's CSS for PDF feature.

See Creating Templates for general info about Laika's template engine.

Overriding Renderers

Apart from adjusting the surrounding template the AST nodes will be rendered into, you can also customize how each individual AST node itself is rendered.

This is a general customization hook in the library and not different from overriding renderers for site output. See Overriding Renderers for more details.