@hackage pdf-slave1.0.0.0

Tool to generate PDF from haskintex templates and YAML input

pdf-slave

Tool that compiles haskintex (TeX with embedded Haskell) files into PDF documents. Templates are described in YAML format and can define dependencies.

Features:

  • Input JSON file for htex file that holds template varying data.

  • Option for packing a template in all-in YAML bundle.

  • Support for template dependencies that include:

    • Bibtex files
    • Images, listings, other static files.
    • Other .htex templates that compiles into TeX and includes into parent template.
    • Other .htex templates that compiles into PDF and includes into parent template.

Template reference

Common template consists of several files:

  • template_input.json - Input data for template in JSON format.
{
  "line-width": 2,
  "spiral-precision": 0.01,
  "spiral-interval": [0,4],
  "spiral-a": 0.1,
  "spiral-b": 4
}
  • template.htex - TeX/LaTeX with embedded Haskell that reads input data from file template.json. You have to provide code at the beginning of file that reads the inputs, like that:
\begin{document}

\begin{haskellpragmas}
{-# LANGUAGE OverloadedStrings #-}
\end{haskellpragmas}
\begin{writehaskell}
import Data.Aeson
import System.IO.Unsafe (unsafePerformIO)
import qualified Data.ByteString.Lazy as BS

data Input = Input {
  lineWidth       :: Double
, spiralPrecision :: Double
, spiralInterval  :: (Double, Double)
, spiralA         :: Double
, spiralB         :: Double
}

instance FromJSON Input where
  parseJSON (Object o) = Input
    <$> o .: "line-width"
    <*> o .: "spiral-precision"
    <*> o .: "spiral-interval"
    <*> o .: "spiral-a"
    <*> o .: "spiral-b"

inpt :: Input
inpt = case unsafePerformIO $ fmap eitherDecode' $ BS.readFile "template_input.json" of
  Left e -> error (show e)
  Right a -> a

\end{writehaskell}
  • template.yaml - description of template and its dependencies.
name:  template01             # name of template
input: template01_input.json  # name of input file
body:  template01.htex        # name of .htex file
dependencies: {}              # dependency tree (see below)
haskintex-opts: []            # additional flags to haskintex

Dependencies

There are 4 different types of dependencies:

  • other - static files that don't require any processing. They could be images, listings etc. Example of YAML configuration:

    dependencies:
      lambda.png: # name of dependency is equal to filename relative to parent template
        type: other # marks type of dependency
      code/demo.hs:
        type: other
    

    See examples/example02 for full example.

  • bibtex - bibliography files that require additional passes with bibtex. Example of YAML configuration:

    dependencies:
      biblio.bib: # name of dependency is equal to filename relative to parent template
        type: bibtex # marks type of dependency
    

    See examples/example03 for full example.

  • template - other .htex templates that are included in parent via \\input{...} or \\include{..}. Example of YAML configuration:

    dependencies:
      dep1: # name of dependency defines subfolder where the output tex file is located
        type:  template # marks type of dependency
        name:  dep1
        input: dep1_input.json
        body:  dep1.htex
      dep2:
        type:  template
        name:  dep2
        body:  dep2.htex
        dependencies:
          lambda.png:
            type: other
          code/demo.hs:
            type: other
    

    See examples/example04 for full example.

    Note that code/demo.hs subdependency should be included as dep2/code/demo.hs in dep2.htex as dep2.tex is inlined into parent.

  • template_pdf - other .htex templates that are included as PDFs into parent template. Example of YAML configuration:

    dependencies:
      template01: # name of dependency defines subfolder where the output tex file is located
        type:  template_pdf # marks type of dependency
        name:  template01
        input: template01_input.json
        body:  template01.htex
      template02:
        type:  template_pdf
        name:  template02
        body:  template02.htex
        dependencies:
          lambda.png:
            type: other
          code/demo.hs:
            type: other
    

    See examples/example05 for full example.

Input propagation

When you work with dependencies you have two options how to handle inputs:

  • Define dependency inputs in its own file:

    dependencies:
      dep1:
        type:  template
        name:  dep1
        input: dep1_input.json # private input file
        body:  dep1.htex
    
  • Define dependency inputs in parent file:

    name:  template06
    input: template06_input.json # contains inputs for dep1
    body:  template06.htex
    dependencies:
      dep1:
        type:  template
        name:  dep1
        body:  dep1.htex
    

    Contents of template06_input.json:

    {
      "dep1": {
        "line-width": 2,
        "spiral-precision": 0.01,
        "spiral-interval": [0,4],
        "spiral-a": 0.1,
        "spiral-b": 4
      }
    }
    

    Note that key of subsection must be equal to name of dependency.

    See examples/example06 for full example.

Making bundles

One can pack all .htex, .json, .yaml and all dependencies in single YAML bundle that can be easily distributed, transmitted between services and stored:

cd examples/template01
pdf-slave --template template01.yaml --output template01_bundle.yaml pack

As modification of such bundles isn't handy, one can unpack bundle:

pdf-slave --template template01_bundle.yaml --output template01_directory unpack

Rendering of bundles is handled with the same command that is used for ordinary templates.

Compilation

You need:

  • LaTeX distribution (for instance, texlive or miktex)

  • stack or system wide GHC 8.0.1 + Cabal 1.24.0.

Compilation with stack:

git clone https://github.com/NCrashed/pdf-slave.git
cd pdf-slave
stack install

Compilation with cabal:

git clone https://github.com/NCrashed/pdf-slave.git
cd pdf-slave
cabal sandbox init
cabal install --dependencies-only
cabal install

Running examples

You need:

  • LaTeX distribution (for instance, texlive or miktex)

  • stack or GHC+Cabal (yes, you need GHC to evaluate templates at runtime)

  • pdf-slave and haskintex executables in PATH

Stack users:

cd examples/template01
stack install aeson HaTeX
stack exec -- pdf-slave --template template01.yaml --output output.pdf pdf && xdg-open output.pdf

Cabal users:

cd examples/template01
cabal sandbox init
cabal install aeson HaTeX
pdf-slave --template template01.yaml --output output.pdf pdf && xdg-open output.pdf

Docker build

  1. Run cook_doocker.sh script. This will build two images, one pdf-slave-build for compilation of binaries and the second one pdf-slave for production usage.

  2. Usage:

docker run -it --rm -v $(pwd)/examples/template01:/data/examples pdf-slave pdf --template examples/template01.yaml --output examples/output.pdf
xdg-open examples/template01/output.pdf
  1. Or download precompiled container from Docker Hub.