{"id":13508952,"url":"https://github.com/gutschilla/elixir-pdf-generator","last_synced_at":"2026-02-19T02:32:30.649Z","repository":{"id":21189818,"uuid":"24497829","full_name":"gutschilla/elixir-pdf-generator","owner":"gutschilla","description":"Create PDFs with wkhtmltopdf or puppeteer/chromium from Elixir.","archived":false,"fork":false,"pushed_at":"2023-04-15T22:45:05.000Z","size":302,"stargazers_count":342,"open_issues_count":29,"forks_count":74,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-11-21T20:12:55.522Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gutschilla.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-09-26T11:59:08.000Z","updated_at":"2025-10-12T16:51:05.000Z","dependencies_parsed_at":"2024-01-08T19:22:19.463Z","dependency_job_id":null,"html_url":"https://github.com/gutschilla/elixir-pdf-generator","commit_stats":{"total_commits":118,"total_committers":28,"mean_commits":4.214285714285714,"dds":"0.31355932203389836","last_synced_commit":"50ab3300a59eb210c1f255a533eee93bb9f7516d"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/gutschilla/elixir-pdf-generator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gutschilla%2Felixir-pdf-generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gutschilla%2Felixir-pdf-generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gutschilla%2Felixir-pdf-generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gutschilla%2Felixir-pdf-generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gutschilla","download_url":"https://codeload.github.com/gutschilla/elixir-pdf-generator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gutschilla%2Felixir-pdf-generator/sbom","scorecard":{"id":450240,"data":{"date":"2025-08-11","repo":{"name":"github.com/gutschilla/elixir-pdf-generator","commit":"50ab3300a59eb210c1f255a533eee93bb9f7516d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.1,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":3,"reason":"Found 5/14 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 23 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"10 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97","Warn: Project is vulnerable to: GHSA-rc47-6667-2j5j","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-pq67-2wwv-3xjx","Warn: Project is vulnerable to: GHSA-8cj5-5rvv-wf4v","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T08:02:08.431Z","repository_id":21189818,"created_at":"2025-08-19T08:02:08.432Z","updated_at":"2025-08-19T08:02:08.432Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29601091,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T00:59:38.239Z","status":"online","status_checked_at":"2026-02-19T02:00:07.702Z","response_time":117,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":"2024-08-01T02:01:00.913Z","updated_at":"2026-02-19T02:32:30.618Z","avatar_url":"https://github.com/gutschilla.png","language":"Elixir","funding_links":[],"categories":["PDF"],"sub_categories":[],"readme":"# PDF Generator\n\n[![CircleCI](https://circleci.com/gh/gutschilla/elixir-pdf-generator.svg?style=svg)](https://circleci.com/gh/gutschilla/elixir-pdf-generator)\n[![Module Version](https://img.shields.io/hexpm/v/pdf_generator.svg)](https://hex.pm/packages/pdf_generator)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/pdf_generator/)\n[![Total Download](https://img.shields.io/hexpm/dt/pdf_generator.svg)](https://hex.pm/packages/pdf_generator)\n[![License](https://img.shields.io/hexpm/l/pdf_generator.svg)](https://github.com/gutschilla/elixir-pdf-generator/blob/master/LICENSE.md)\n[![Last Updated](https://img.shields.io/github/last-commit/gutschilla/elixir-pdf-generator.svg)](https://github.com/gutschilla/elixir-pdf-generator/commits/master)\n\nA wrapper for both wkhtmltopdf and chrome-headless plus PDFTK (adds in\nencryption) for use in Elixir projects.\n\nSee [Changelog](./CHANGELOG.md) for recent changes.\n\n## Usage\n\n_Hint:_ In IEx, `h PdfGenerator.generate` is your friend.\n\nFor Elixir version earlier than 1.4:\n\n```elixir\ndef application do\n    [\n      applications: [\n        :logger,\n        :pdf_generator\n      ]\n    ]\nend\n```\n\nAdd this to your dependencies in your mix.exs:\n\n```elixir\ndefp deps do\n[\n  # ... whatever else\n  {:pdf_generator, \"\u003e=0.6.0\" }, # \u003c-- and this\n]\nend\n```\n\nIf you want to use a locally-installed chromium in **RELEASES** (think `mix\nrelease`), alter your mixfile to let `make` take care of compilation and\ndependency-fetching:\n\n```elixir\ndefp deps do\n  [\n    {:pdf_generator, \"\u003e=0.6.2\", compile: \"make chrome\"}\n  ]\nend\n```\nTo get the latest version or if you run into issues:\n\n```elixir\ndefp deps do\n  [\n    {:pdf_generator, \"~\u003e 0.6.2\", github: \"gutschilla/elixir-pdf-generator\", compile: \"make chrome\"}\n  ]\nend\n```\n\nThis will embed a **300 MB** (yes, that large) Chromium binary into your priv folder\nwhich will survive packaging as Erlang release. This _can_ be handy as this will\nrun on slim Alpine docker images with just NodeJS installed.\n\nThe recommended way still is to install Chromium/Puppeteer globally and set the\n`prefer_system_executable: true` option when generating PDFs.\n\nIn development: While this usually works, it unfortunately leads to\npdf_generator to be compiled all the time again and again due to my bad Makefile\nskills. Help is very much appreciated.\n\nEventually, if you are using Phoenix and you would like to have your npm\npackages installed locally, within the `/assets/node_modules` directory, simply\nrun `npm install chrome-headless-render-pdf puppeteer` within\n`assets/node_modules` and pass `prefer_local_executable: true` option when\ngenerating the PDF like this:\n\n```elixir\nPdfGenerator.generate(url, generator: :chrome, prefer_local_executable: true)\n```\n\n## Try it out\n\nPass some HTML to PdfGenerator.generate:\n\n```bash\n$ iex -S mix\n\nhtml = \"\u003chtml\u003e\u003cbody\u003e\u003cp\u003eHi there!\u003c/p\u003e\u003c/body\u003e\u003c/html\u003e\"\n# be aware, this may take a while...\n{:ok, filename}    = PdfGenerator.generate(html, page_size: \"A5\")\n{:ok, pdf_content} = File.read(filename)\n\n# or, if you prefer methods that raise on error:\nfilename = PdfGenerator.generate!(html, generator: :chrome)\n```\n\nOr, pass some URL\n\n```elixir\nPdfGenerator.generate {:url, \"http://google.com\"}, page_size: \"A5\"\n```\n\nOr use the bang-methods:\n\n```elixir\nfilename   = PdfGenerator.generate! \"\u003chtml\u003e...\"\npdf_binary = PdfGenerator.generate_binary! \"\u003chtml\u003e...\"\n```\n\n### Chrome\n\nOr, use **chrome-headless**.\n\nUnless your mixfile says `{:pdf_generator, \"\u003e=6.0.0\", compile: \"make chrome\"}`\nChrome won't be installed into your application. Please set the\n`prefer_system_executable: true` option in this case.\n\n```elixir\nhtml_works_too = \"\u003chtml\u003e\u003cbody\u003e\u003ch1\u003eMinimalism!\"\n{:ok, filename} = PdfGenerator.generate html_works_too, generator: :chrome, prefer_system_executable: true\n```\n\n### Docker\n\nIf using chrome in a superuser/root environment (read: **docker**), make sure to\npass an option to chrome to disable sandboxing. And be aware of the implications.\n\n```elixir\nhtml_works_too = \"\u003chtml\u003e\u003cbody\u003e\u003ch1\u003eI need Docker, baby docker is what I need!\"\n{:ok, filename} = PdfGenerator.generate html_works_too, generator: :chrome, no_sandbox: true, page_size: \"letter\"\n```\n\n## System prerequisites\n\nIt's either\n\n* wkhtmltopdf or\n\n* NodeJS (for Chrome-headless/Puppeteer)\n\n### Chrome-headless\n\nThis will allow you to make more use of Javascript and advanced CSS as it's just\nyour Chrome/Chromium browser rendering your web page as HTML and printing it as\nPDF. Rendering _tend_ to be a bit faster than with wkhtmltopdf. The price tag is\nthat PDFs printed with chrome/chromium are usually considerably bigger than\nthose generated with wkhtmltopdf.\n\n### Global Install (great for Docker images)\n\nRun `npm -g install chrome-headless-render-pdf puppeteer`.\n\nThis requires [nodejs](https://nodejs.org), of course. This will install a\nrecent Chromium and chromedriver to run Chrome in headless mode and use this\nbrowser and its API to print PDFs globally on your machine.\n\nIf you prefer a project-local install, use the `compile: \"make chrome\"` option\nin your mixfile's dependency-line.\n\nOn some machines, this doesn't install Chromium and fails. Here's how to get\nthis running on Ubuntu 18:\n\n```bash\nDEBIAN_FRONTEND=noninteractive PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=TRUE \\\n  apt-get install -y chromium-chromedriver \\\n  \u0026\u0026 npm -g install chrome-headless-render-pdf puppeteer\n```\n\n### Local Install\n\nRun `make priv/node_modules`. This requires both `nodejs` (installation see\nabove) and `make`.\n\nOr, run `cd priv \u0026\u0026 npm install`\n\n### wkhtmltopdf\n\n- **Alpine** (tested on 3.11): `apk add wkhtmltopdf` - gone are the days of\n  manually fumbling around with wkhtmltopdf and its muss preference over glibc.\n\n- **Ubuntu 19.10+**: `apt-get install wkhtmltopdf` and you'll have 0.12.5 on $PATH\n\n- **Ubuntu 18.04**: Download wkhtmltopdf and place it in your $PATH. Current\n  binaries can be found here: http://wkhtmltopdf.org/downloads.html\n\n  For the impatient (Ubuntu 18.04 Bionic Beaver):\n\n  ```bash\n  apt-get -y install xfonts-base xfonts-75dpi \\\n    \u0026\u0026 wget https://downloads.wkhtmltopdf.org/0.12/0.12.5/wkhtmltox_0.12.5-1.bionic_amd64.deb \\\n    \u0026\u0026 dpkg -i wkhtmltox_0.12.5-1.bionic_amd64.deb\n  ```\n\n  For other distributions, refer to http://wkhtmltopdf.org/downloads.html – For\n  example, replace `bionic` with `xenial` if you're on Ubuntu 16.04.\n\n## Optional Dependencies\n\n3. _optional:_ Install `xvfb` (shouldn't be required with the binary mentioned above):\n\n   To use other wkhtmltopdf executables compiled with an unpatched Qt on systems\n   without an X window server installed, please install `xvfb-run` from your\n   repository (on Debian/Ubuntu: `sudo apt-get install xvfb`).\n\n   I am glad to have received feedback that people are actually using this\n   feature.\n\n4. _optional:_ Install `pdftk` via your package manager or homebrew. The project\n   page also contains a Windows installer. On Debian/Ubuntu just type:\n   `apt-get -y install pdftk`\n\n## Options and Configuration\n\nThis module will automatically try to find both `wkhtmltopdf` and `pdftk` in\nyour path. But you may override or explicitly set their paths in your\n`config/config.exs`.\n\n```elixir\nconfig :pdf_generator,\n    wkhtml_path:    \"/usr/bin/wkhtmltopdf\",   # \u003c-- this program actually does the heavy lifting\n    pdftk_path:     \"/usr/bin/pdftk\"          # \u003c-- only needed for PDF encryption\n```\n\nor, if you prefer chrome-headless\n\n```\nconfig :pdf_generator,\n    use_chrome: true,                           # \u003c-- make sure you installed node/puppeteer\n    prefer_system_executable: true              # \u003c-- set this if you installed the NPM dependencies globally\n    raise_on_missing_wkhtmltopdf_binary: false, # \u003c-- so the app won't complain about a missing wkhtmltopdf\n```\n\n### More options\n\n- `filename` - filename for the output PDF file (without .pdf extension,\n  defaults to a random string)\n\n- `page_size` - defaults to `\"A4\"`, see `wkhtmltopdf` for more options.\n  `\"letter\"` (for US letter) be translated to 8x11.5 inches (currently, only in\n  chrome)\n\n- `open_password` - requires `pdftk`, set password to encrypt PDFs with\n\n- `edit_password` - requires `pdftk`, set password for edit permissions on PDF\n\n- `shell_params` - pass custom parameters to `wkhtmltopdf` or `chrome-headless-render-pdf`. **CAUTION: BEWARE OF SHELL INJECTIONS!**\n\n- `command_prefix`- prefix `wkhtmltopdf` with some command or a command with\n  options (e.g. `xvfb-run -a`, `sudo` ..)\n\n- `delete_temporary` - immediately remove temp files after generation\n\n## Contribution\n\nYou're more than welcome to submit patches. Please run `mix test` to ensure at\nbit of stability. Tests require a full-fledged environment, with all of\n`wkhtmltopdf`, `xvfb` and `chrome-headless-render-pdf` available path. Also\nmake to to have run `npm install` in the app's base directory (will install\nchrome-headless-render-pdf non-globally in there). With all these installed,\n`mix test` should run smoothly.\n\n_Hint_: Getting `:enoent` errors usually means that chrome or xvfb couldn't be\nrun. Yes, this should output a nicer error.\n\n## Heroku Setup\n\nIf you want to use this project on Heroku, you can use buildpacks instead of\nbinaries to load `pdftk` and `wkhtmltopdf`:\n\n```\nhttps://github.com/fxtentacle/heroku-pdftk-buildpack\nhttps://github.com/dscout/wkhtmltopdf-buildpack\nhttps://github.com/HashNuke/heroku-buildpack-elixir\nhttps://github.com/gjaldon/phoenix-static-buildpack\n```\n\n__note:__ The list also includes Elixir and Phoenix buildpacks to show you that they\nmust be placed after `pdftk` and `wkhtmltopdf`. It won't work if you load the\nElixir and Phoenix buildpacks first.\n\n## Running non-patched wkhtmltopdf headless\n\nThis section only applies to `wkhtmltopdf` users using wkhtmltopdf w/o the qt patch. If you are using the latest 0.12 binaries from https://downloads.wkhtmltopdf.org (recommended) you can safely skip this section.\n\nIf you want to run `wkhtmltopdf` with an unpatched version of webkit that requires\nan X Window server, but your server (or Mac) does not have one installed,\nyou may find the `command_prefix` handy:\n\n```elixir\nPdfGenerator.generate \"\u003chtml..\", command_prefix: \"xvfb-run\"\n```\n\nThis can also be configured globally in your `config/config.exs`:\n\n```elixir\nconfig :pdf_generator,\n    command_prefix: \"/usr/bin/xvfb-run\"\n```\n\nIf you will be generating multiple PDFs simultaneously, or in rapid succession,\nyou will need to configure `xvfb-run` to search for a free X server number,\nor set the server number explicitly. You can use the `command_prefix` to pass\noptions to the `xvfb-run` command.\n\n```elixir\nconfig :pdf_generator,\n    command_prefix: [\"xvfb-run\", \"-a\"]\n```\n\n## Documentation\n\nFor more info, read the [docs on hex](http://hexdocs.pm/pdf_generator) or issue\n`h PdfGenerator.generate` in your iex shell.\n\n## Known issues\n\nUnfortunately, with Elixir 1.7+ `System.cmd` seems to pass parameters\ndifferently to the environment than it did before, now requiring shell options\nlike `--foo=bar` to be split up as `[\"--foo\", \"bar\"]`. This behaviour seemingly\nwent away with OTP 22 in May 2019 and Elixir 1.8.2. So if you run into issues,\ntry upgrading to the latest Erlang/OTP and Elixir first, and do not hesitate\nfile a report.\n\n## Contributing\n\nContributions (Issues, PRs…) are more than welcome. Please have a quick read at\nthe [Contribution tips](./CONTRIBUTING.md), though. It's basically about scope\nand kindness.\n\n## Copyright and License\n\nCopyright (c) 2014 Martin Gutsch\n\nReleased under the MIT License, which can be found in [LICENSE.md](./LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgutschilla%2Felixir-pdf-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgutschilla%2Felixir-pdf-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgutschilla%2Felixir-pdf-generator/lists"}