jonnycharles

jonnycharles

I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions about this topic in the past, I’m interested in any recent developments or current libraries that the community recommends. Key features I’m looking for include support for complex layouts, text styling, and custom tables. Any insights or suggestions would be greatly appreciated!

Showing Posts 1 to 10

Hermanverschooten

Hermanverschooten

There (sadly) is no real equivalence to Prawn for Elixir.

There are 2 libraries, pdf and mudbrick. The first is more mature, uses GenServers to store the state of the pdf being build, where the second one is very new and still lacking a lot of features, but it uses a struct to store the state.
Mudbrick is easy to extend with your own features, where pdf is practically impossible to extend.
Mudbrick supports OpenType (otf) fonts, pdf, adobe type mananger (atm).

If you do not want to shell out to something like htmltopdf, these are currently the most feasible options.

The font-handling in pdf was recently rewritten, making it compile several times faster.

I have been using pdf for several years, tried mudbrick, I like it, but is not yet there.

10
Post #1
kokolegorille

kokolegorille

If You really miss prawn, You can run it in Elixir with erlport…

_io2

_io2

We have had great success with https://wkhtmltopdf.org/

Within our phoenix application, a simple GenServer calls out to the wkhtmltopdf binary, passing along generated html and returning the resulting pdf file.

The html itself is generated from a bunch of $template.html.heex files and for each new PDF document type we simply add a new *.html.heex file.

We produce a lot of different types of pdf reports, and regularly add new ones so this approach (converting html → pdf) makes it easy to assign that task to anyone who can write html, and allows us to produce some very rich, and complex page / document designs.

dimitarvp

dimitarvp

I wanted to bring it up but assumed they were not okay with the Chromium dependence.

lccezinha

lccezinha

Here we are using GitHub - gutschilla/elixir-pdf-generator: Create PDFs with wkhtmltopdf or puppeteer/chromium from Elixir. · GitHub for simple PDF and it has been working fine for the last years

outlog

outlog

+1 for wkhtmltopdf

egze

egze

Nice. Didn’t know about mudbrick. A modern native Elixir PDF writer would be so cool for the ecosystem.

mindok

mindok

It depends what you’re looking for, but we use typst (https://typst.app/). We use it to generate high quality output for work instructions (images, pixel perfect layout, table of contents etc etc). Having used it for that, I’d also use it for things like database reports, invoice generation etc. It’s also deterministic - it doesn’t rely on browser engines etc to interpret CSS, so once you have placed elements on a page, they stay put.

There’s a command-line version that compiles to a single binary (it’s written in Rust, so easy enough to add to your docker builder image for most platforms [I think that’s the lingo - I’m no docker whiz]. Build time is a couple of minutes, but the guys at Alembic designed the docker build to minimise the likelihood that it needs to be recompiled for each deploy). We’re currently just calling it with System.cmd. The main downer is you have to assemble all the inputs (e.g. images, JSON data extracts) into the directory where the main .typ file is, so no referencing images on the web. There are Elixir bindings, but for our use-case isn’t wasn’t worth the extra dependency.

The output quality is awesome (it is designed as a Latex successor). Coding up the layout is very similar to composing views with Phoenix function components. Some of the syntax takes a bit of getting used to, but it’s still the least fighting I’ve been through to get nice quality output from a database to a PDF or printer, by a long way, in >30 years of doing this kind of stuff.

Edit: PS - tables allow fine control on layout, styling, row/col-spans etc.

17
Post #9
outlog

outlog

Took a look at what I used last time around, and it was https://weasyprint.org, probably due to the nice templates out of the box.. you render the html, path to the css file, and call it using Rambo (you might need {:rambo, github: "/myobie/rambo", branch: "aarch64-apple"},)..

defmodule RamboPdf do
  def create_pdf(item) do
    css = Path.join([PDFfile.path(), "templates/invoice", "invoice.css"])

    # grab data, and EEx.eval_file with the template file
    html =
      PDF.gen_data(item)
      |> PDF.populate_html("templates/invoice", "invoice.html")

    output_file = Path.join([PDFfile.path(), "output", "#{item.room}.pdf"])
    # https://doc.courtbouillon.org/weasyprint/stable/api_reference.html#command-line-api

    task =
      Task.async(fn ->
        Rambo.run("weasyprint", ["--encoding", "utf8", "-q", "-s", css, "-", "-"],
          in: html,
          log: false,
          timeout: 20_000
        )

        # System.cmd("weasyprint", ["--encoding", "utf8", "-q", "-s", css, "-", "-", html])
      end)

    task_output = Task.await(task, :infinity)

    case task_output do
      {:ok, %Rambo{err: _err, out: output, status: 0}} ->
        File.write(output_file, output, [:binary])
        output

      error ->
        IO.inspect("error")
        IO.inspect(error)
    end
  end
end

Where Next? Top

Trending in Questions Top

Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
matt-savvy
Anyone here using Honeybadger? My Honeybadger account is being overwhelmed with noise from some bots. Seeing a lot of Bandit.HTTPError...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews