{"id":28551831,"url":"https://github.com/ncrashed/pdf-slave","last_synced_at":"2025-07-03T17:30:42.043Z","repository":{"id":56874751,"uuid":"76850418","full_name":"NCrashed/pdf-slave","owner":"NCrashed","description":"Service for rendering PDF documents from haskintex templates and YAML inputs","archived":false,"fork":false,"pushed_at":"2017-06-29T15:37:47.000Z","size":95,"stargazers_count":5,"open_issues_count":1,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-10T04:07:08.181Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NCrashed.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-19T10:00:16.000Z","updated_at":"2020-05-24T03:22:24.000Z","dependencies_parsed_at":"2022-08-20T22:30:38.600Z","dependency_job_id":null,"html_url":"https://github.com/NCrashed/pdf-slave","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/NCrashed/pdf-slave","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NCrashed%2Fpdf-slave","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NCrashed%2Fpdf-slave/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NCrashed%2Fpdf-slave/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NCrashed%2Fpdf-slave/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NCrashed","download_url":"https://codeload.github.com/NCrashed/pdf-slave/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NCrashed%2Fpdf-slave/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263369403,"owners_count":23456297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-10T04:07:08.603Z","updated_at":"2025-07-03T17:30:42.038Z","avatar_url":"https://github.com/NCrashed.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"pdf-slave\n=========\n\n[![Build Status](https://travis-ci.org/NCrashed/pdf-slave.svg?branch=master)](https://travis-ci.org/NCrashed/pdf-slave)\n\nTool that compiles [haskintex](http://daniel-diaz.github.io/projects/haskintex/) (TeX with embedded Haskell) files into PDF documents.\nTemplates are described in YAML format and can define dependencies.\n\nFeatures:\n\n* Input JSON file for `htex` file that holds template varying data.\n\n* Option for packing a template in all-in YAML bundle.\n\n* Support for template dependencies that include:\n  - Bibtex files\n  - Images, listings, other static files.\n  - Other `.htex` templates that compiles into TeX and includes into parent template.\n  - Other `.htex` templates that compiles into PDF and includes into parent template.\n\nDescription\n===========\n\nIn many real-world systems we need to produce reports, cheques and other documents\nto users. One possible solution is rendering LaTeX files, but it is not flexible\nenough as you need to solve burden with generation of LaTeX file from varying inputs,\nmanage static files like images and handling dependencies between pieces of document.\n\nThe new tool takes the burden away. Now all static files and generation code is\nlocated within a single template project, that describes how to build your PDF document in a declaretive way.\n\nCommon work flow with pdf-slave:\n* Develop template from several LaTeX files with embedded Haskell (thanks to [haskintex](http://daniel-diaz.github.io/projects/haskintex/)\n tool)\n\n* Pack the template project into bundle all-in file.\n\n* Distribute the bundle (for instance to your service server).\n\n* Call pdf-slave with bundle and inputs in JSON file to generate PDF document.\n\nTemplate reference\n==================\n\nCommon template consists of several files:\n\n* `template_input.json` - Input data for template in JSON format.\n\n  ``` JSON\n  {\n    \"line-width\": 2,\n    \"spiral-precision\": 0.01,\n    \"spiral-interval\": [0,4],\n    \"spiral-a\": 0.1,\n    \"spiral-b\": 4\n  }\n  ```\n\n* `template.htex` - TeX/LaTeX with embedded Haskell that reads input data from\nfile `template.json`. You have to provide code at the beginning of file that reads\nthe inputs, like that:\n\n  Make a `Helper.hs` file in directory with template:\n  ``` haskell\n  module Helper where\n\n  import qualified Data.ByteString.Lazy as BS\n  import Data.Aeson\n  import System.IO.Unsafe\n\n  defaultInput :: FromJSON a =\u003e a\n  {-# NOINLINE defaultInput #-}\n  defaultInput = case unsafePerformIO $ fmap eitherDecode' $ BS.readFile \"input.json\" of\n    Left e -\u003e error (show e)\n    Right a -\u003e a\n  ```\n\n  Next in your `.htex` file:\n  ``` Haskell\n  \\begin{document}\n\n  \\begin{haskellpragmas}\n  {-# LANGUAGE OverloadedStrings #-}\n  \\end{haskellpragmas}\n  \\begin{writehaskell}\n  import Data.Aeson\n  import Helper\n\n  data Input = Input {\n    lineWidth       :: Double\n  , spiralPrecision :: Double\n  , spiralInterval  :: (Double, Double)\n  , spiralA         :: Double\n  , spiralB         :: Double\n  }\n\n  instance FromJSON Input where\n    parseJSON (Object o) = Input\n      \u003c$\u003e o .: \"line-width\"\n      \u003c*\u003e o .: \"spiral-precision\"\n      \u003c*\u003e o .: \"spiral-interval\"\n      \u003c*\u003e o .: \"spiral-a\"\n      \u003c*\u003e o .: \"spiral-b\"\n\n  inpt :: Input\n  inpt = defaultInput\n  \\end{writehaskell}\n  ```\n\n  Note: The tool copies JSON with inputs to build folder with .htex twice, once with\n  name specified at `input` key in template description and secondly at fixed `input.json`.\n\n* `template.yaml` - description of template and its dependencies.\n\n  ``` YAML\n  name:  template01             # name of template\n  input: template01_input.json  # name of input file\n  body:  template01.htex        # name of .htex file\n  dependencies: {}              # dependency tree (see below)\n  haskintex-opts: []            # additional flags to haskintex\n  ```\n\n  For input `Helper.hs` you should make a record to inform `pdf-slave` that the module should be copied to build directory:\n\n  ``` YAML\n  dependencies:\n    Helper.hs:\n      type: other\n  ```\n\n## Dependencies\n\nThere are 4 different types of dependencies:\n\n* `other` - static files that don't require any processing. They could be images,\nlistings etc. Example of YAML configuration:\n\n  ``` YAML\n  dependencies:\n    lambda.png: # name of dependency is equal to filename relative to parent template\n      type: other # marks type of dependency\n    code/demo.hs:\n      type: other\n  ```\n\n  See [examples/example02](https://github.com/NCrashed/pdf-slave/tree/master/examples/template02) for full example.\n\n* `bibtex` - bibliography files that require additional passes with `bibtex`. Example of YAML configuration:\n\n  ``` YAML\n  dependencies:\n    biblio.bib: # name of dependency is equal to filename relative to parent template\n      type: bibtex # marks type of dependency\n  ```\n\n  See [examples/example03](https://github.com/NCrashed/pdf-slave/tree/master/examples/template03) for full example.\n\n* `template` - other `.htex` templates that are included in parent via `\\\\input{...}` or `\\\\include{..}`. Example of YAML configuration:\n\n  ``` YAML\n  dependencies:\n    dep1: # name of dependency defines subfolder where the output tex file is located\n      type:  template # marks type of dependency\n      name:  dep1\n      input: dep1_input.json\n      body:  dep1.htex\n    dep2:\n      type:  template\n      name:  dep2\n      body:  dep2.htex\n      dependencies:\n        lambda.png:\n          type: other\n        code/demo.hs:\n          type: other\n  ```\n\n  See [examples/example04](https://github.com/NCrashed/pdf-slave/tree/master/examples/template04) for full example.\n\n  **Note that `code/demo.hs` subdependency should be included as `dep2/code/demo.hs` in `dep2.htex` as `dep2.tex` is inlined into parent.**\n\n* `template_pdf` - other `.htex` templates that are included as PDFs into parent template. Example of YAML configuration:\n\n  ``` YAML\n  dependencies:\n    template01: # name of dependency defines subfolder where the output tex file is located\n      type:  template_pdf # marks type of dependency\n      name:  template01\n      input: template01_input.json\n      body:  template01.htex\n    template02:\n      type:  template_pdf\n      name:  template02\n      body:  template02.htex\n      dependencies:\n        lambda.png:\n          type: other\n        code/demo.hs:\n          type: other\n  ```\n\n  See [examples/example05](https://github.com/NCrashed/pdf-slave/tree/master/examples/template05) for full example.\n\n### Input propagation\n\nWhen you work with dependencies you have two options how to handle inputs:\n\n* Define dependency inputs in its own file:\n\n  ``` YAML\n  dependencies:\n    dep1:\n      type:  template\n      name:  dep1\n      input: dep1_input.json # private input file\n      body:  dep1.htex\n  ```\n\n* Define dependency inputs in parent file:\n\n  ``` YAML\n  name:  template06\n  input: template06_input.json # contains inputs for dep1\n  body:  template06.htex\n  dependencies:\n    dep1:\n      type:  template\n      name:  dep1\n      body:  dep1.htex\n  ```\n\n  Contents of `template06_input.json`:\n\n  ``` JSON\n  {\n    \"dep1\": {\n      \"line-width\": 2,\n      \"spiral-precision\": 0.01,\n      \"spiral-interval\": [0,4],\n      \"spiral-a\": 0.1,\n      \"spiral-b\": 4\n    }\n  }\n  ```\n\n  Note that key of subsection must be equal to name of dependency.\n\n  See [examples/example06](https://github.com/NCrashed/pdf-slave/tree/master/examples/template06) for full example.\n\n## Making bundles\n\nOne can pack all `.htex`, `.json`, `.yaml` and all dependencies in single YAML\nbundle that can be easily distributed, transmitted between services and stored:\n\n``` bash\ncd examples/template01\npdf-slave --template template01.yaml --output template01_bundle.yaml pack\n```\n\nAs modification of such bundles isn't handy, one can unpack bundle:\n\n``` bash\npdf-slave --template template01_bundle.yaml --output template01_directory unpack\n```\n\nRendering of bundles is handled with the same command that is used for ordinary\ntemplates.\n\nCompilation\n===========\n\nYou need:\n\n* LaTeX distribution (for instance, texlive or miktex)\n\n* [stack](https://docs.haskellstack.org/en/stable/README/) or system wide GHC 8.0.1 + Cabal 1.24.0.\n\nCompilation with stack:\n``` bash\ngit clone https://github.com/NCrashed/pdf-slave.git\ncd pdf-slave\nstack install\n```\n\nCompilation with cabal:\n``` bash\ngit clone https://github.com/NCrashed/pdf-slave.git\ncd pdf-slave\ncabal sandbox init\ncabal install --dependencies-only\ncabal install\n```\n\nRunning examples\n================\n\nYou need:\n\n* LaTeX distribution (for instance, texlive or miktex)\n\n* stack or GHC+Cabal (yes, you need GHC to evaluate templates at runtime)\n\n* `pdf-slave` and `haskintex` executables in PATH\n\nStack users:\n``` bash\ncd examples/template01\nstack install aeson HaTeX\nstack exec -- pdf-slave --template template01.yaml --output output.pdf pdf \u0026\u0026 xdg-open output.pdf\n```\n\nCabal users:\n``` bash\ncd examples/template01\ncabal sandbox init\ncabal install aeson HaTeX\npdf-slave --template template01.yaml --output output.pdf pdf \u0026\u0026 xdg-open output.pdf\n```\n\nDocker build\n============\n\n1. 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.\n\n2. Usage:\n\n  ``` bash\n  docker run -it --rm -v $(pwd)/examples/template01:/data/examples pdf-slave pdf --template examples/template01.yaml --output examples/output.pdf\n  xdg-open examples/template01/output.pdf\n  ```\n\n3. Or download [precompiled container](https://hub.docker.com/r/ncrashed/pdf-slave/) from Docker Hub.\n\n\nCredits\n=======\n\n* Daniel Díaz - author of `haskintex` tool that is core of the package.\n\n* Alexander Vershilov aka qnikst - help with debugging and new `Helper.hs` module.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncrashed%2Fpdf-slave","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fncrashed%2Fpdf-slave","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncrashed%2Fpdf-slave/lists"}