DEV Community

Cover image for Generate PDF with Ferrum (headless Chrome API)
Yaroslav Shmarov
Yaroslav Shmarov

Posted on • Originally published at blog.corsego.com on

Generate PDF with Ferrum (headless Chrome API)

Thanks to URLBOX for sponsoring this blogpost! Convert URL to PNG/PDF with UrlBox screenshot API. Urlbox also helps to block Ads & Popups, Bypass Captchas, Auto-Accept Cookies.


Usually I would use an HTML-to-PDF library to to generate and display a PDF.

An absolutely different , alternative way to view or download a page as PDF would be via a headless browser API.

Gem Ferrum lets you open a headless chrome browser and perform different actions (click link, take screenshot, open as PDF, etc.)

Why not use Ferrum to open or save a file as PDF?

Here’s how it could work:

Example of an HTML page ⤵️

Ferrum HTML page

Clicking the “View as PDF” link would open a link as PDF ⤵️

Ferrum page turned into PDF

Install and use Gem Ferrum

Install the gem:

# Gemfile
gem "ferrum"

Enter fullscreen mode Exit fullscreen mode

Add a route:

# config/routes.rb
get 'home/index'

Enter fullscreen mode Exit fullscreen mode

Add an HTML page.

You can add a link_to render the page as PDF.

Notice I add a class .no-print, so that the link does not get displayed in print media type.

<!-- app/views/home/index.html.erb -->
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>
<div class="no-print">
  <%= link_to "View as PDF", home_index_path(format: :pdf) %>
</div>

Enter fullscreen mode Exit fullscreen mode

Add .no-print CSS class to elements that should not be printable:

/* app/assets/stylesheets/application.css */
@media print {
  .no-print {
    display: none !important;
  }
}

/* other css classes you might want to add */
@media print {
  body {
    -webkit-print-color-adjust: exact;
    background: #fff;
    background-color: #fff;
    float: none;
    display: block;
  }
  .no_margin {
    padding-left: 0px !important;
  }
  .no-print {
    display: none !important;
  }
  .printer-preview-content,
  .printer-preview-content_landscape {
    max-width: 100% !important;
    width: 100% !important;
    height: auto !important;
    padding: 0 !important;
    margin: 0 !important;
  }
  .cover_div {
    display: table;
  }
}

Enter fullscreen mode Exit fullscreen mode

Finally, use Ferrum to navigate to an internal or external URL and display it as PDF:

# app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    respond_to do |format|
      format.html
      format.pdf do
        handle_pdf_format
      end
    end
  end

  private

  def handle_pdf_format
    filename = controller_name
    tmp = Tempfile.new("pdf-chrome-#{filename}")
    browser = Ferrum::Browser.new
    # browser.go_to("http://localhost:3000/home/index")
    browser.go_to(home_index_url)
    # browser.go_to("https://google.com")
    # click_on_text "Accept all"
    # browser.at_css(".QS5gu.sy4vM").click
    sleep(0.3)
    browser.pdf(
      path: tmp.path,
      format: "A4".to_sym,
      landscape: false,
      # margin: {top: 36, right: 36, bottom: 36, left: 36},
      # preferCSSPageSize: true,
      # printBackground: true
    )
    browser.quit
    pdf_data = File.read(tmp.path)
    pdf_filename = "#{filename}.pdf"
    send_data(pdf_data,
              filename: pdf_filename,
              type: "application/pdf",
              disposition: "inline")
  ensure
    tmp.close
    tmp.unlink
  end
end

Enter fullscreen mode Exit fullscreen mode

It works well for publicly accessible URLs, however it is not so straightforwar for links that require current_user authentication. I’ve asked a question here https://github.com/rubycdp/ferrum/issues/423 and am hoping for an easy enough solution 🤠

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs