page_print is a Ruby gem with a native C extension that renders HTML strings to PDF files using the plutobook library.
- Ruby 3.0+
- Native gems are published for
x86_64-linuxandarm64-darwin. - The
arm64-darwingem vendors PlutoBook but compiles the small Ruby extension during install so it links against your local Ruby. - Source builds on unsupported platforms require PlutoBook development headers and library files.
On macOS with Homebrew:
brew install plutobook pkg-configIf pkg-config cannot find plutobook, install the gem with explicit include and library paths:
gem install page_print -- --with-plutobook-include=/path/to/include --with-plutobook-lib=/path/to/libAdd PagePrint to your Gemfile:
gem "page_print", "~> 0.1.2"Or install from RubyGems directly:
gem install page_printThe native gems bundle PlutoBook and required non-system shared libraries. Optional PlutoBook features for curl, TurboJPEG, and WebP are disabled in native gems to keep the bundled dependency set smaller.
| Platform | Install Type |
|---|---|
x86_64-linux |
Native gem |
arm64-darwin |
Vendored PlutoBook, local Ruby extension build |
| Other platforms | Source build |
Build and install locally:
gem build page_print.gemspec
gem install ./page_print-*.gem- Install development dependencies:
bundle install- Compile the native extension into
lib/page_print:
bundle exec rake compile- Open an interactive Ruby session against the local checkout:
bundle exec irb -IlibThen load the gem from the repo and try it:
require "page_print"
require "tmpdir"
output_path = File.join(Dir.tmpdir, "page_print-output.pdf")
PagePrint.html_to_pdf("<html><body><h1>Hello</h1></body></html>", output_path, page_size: :letter, margins: :narrow, media: :screen)You can also do a quick one-shot smoke test from the shell:
bundle exec ruby -Ilib -e 'require "tmpdir"; require "page_print"; output_path = File.join(Dir.tmpdir, "page_print-output.pdf"); p PagePrint.html_to_pdf("<html><body><h1>Hello</h1></body></html>", output_path, page_size: :letter, margins: :narrow, media: :screen)'Or use the development console, which compiles the native extension first and then starts IRB with PagePrint loaded:
bin/consoleRun the test suite only:
bundle exec rake testOr run the default rake task, which compiles the extension and then runs tests:
bundle exec rakeBuild an x86_64-linux platform gem with a vendored PlutoBook library:
bundle exec rake package:linuxBuild an Apple Silicon macOS platform gem with a vendored PlutoBook library:
bundle exec rake package:darwin_arm64These tasks check out PlutoBook v0.17.0, build it into lib/page_print/vendor/<platform>, and write a platform gem to pkg/. The Linux package includes a precompiled Ruby extension. The macOS package compiles the Ruby extension during gem install to avoid hardcoding the build machine's Ruby path.
Native gems bundle PlutoBook and its non-system shared library dependencies. Optional PlutoBook features for curl, TurboJPEG, and WebP are disabled to keep the bundled dependency set smaller.
The packaging tasks expect PlutoBook's build dependencies to be installed on the build machine, including Meson, Ninja, pkg-config, Cairo, FreeType, HarfBuzz, Fontconfig, Expat, and ICU.
PagePrint is currently optimized for Rails applications using Propshaft. In Rails, PagePrint installs a default Propshaft-backed resource fetcher and uses the current request URL as the default base_url.
Render a PDF from a controller:
class PrintsController < ApplicationController
def pdf
html = render_to_string(template: "prints/pdf", formats: [:html], layout: "pdf")
pdf = PagePrint.html_to_pdf_string(
html,
page_size: :a4,
margins: :normal,
media: :print,
metadata: { title: "Print PDF", author: "PagePrint" }
)
send_data pdf, filename: "print.pdf", type: "application/pdf", disposition: "inline"
end
endUse normal Rails asset helpers in the PDF template or layout:
<%= stylesheet_link_tag "pdf" %>
<%= image_tag "logo.png" %>During controller actions, PagePrint defaults base_url to request.base_url. The default Rails resource fetcher resolves /assets/... through Propshaft or public/assets, avoiding HTTP requests back to the Rails app.
You can still override base_url explicitly:
pdf = PagePrint.html_to_pdf_string(html, base_url: "https://example.com")Override the fetcher only when needed:
# config/initializers/page_print.rb
PagePrint.configure do |config|
config.resource_fetcher = MyResourceFetcher.new
endrequire "page_print"
require "tmpdir"
html = <<~HTML
<html>
<body>
<h1>Hello</h1>
<p>This PDF was generated by PagePrint.</p>
</body>
</html>
HTML
output_path = File.join(Dir.tmpdir, "page_print-output.pdf")
PagePrint.html_to_pdf(html, output_path, base_url: "https://example.com")To get the generated PDF as a binary string instead of writing directly to a file:
pdf = PagePrint.html_to_pdf_string(html, base_url: "https://example.com")Use custom page dimensions and margins when a preset is not enough:
pdf = PagePrint.html_to_pdf_string(
html,
page_size: { width: 100, height: 150, unit: :mm },
margins: { top: 5, right: 6, bottom: 7, left: 8, unit: :mm }
)You can configure default options once, for example to provide a resource fetcher used by all renders:
PagePrint.configure do |config|
config.resource_fetcher = lambda do |url|
next unless url == "asset:pdf.css"
{ content: "body { font-family: sans-serif; }", mime_type: "text/css" }
end
endSupported keyword options:
base_url:string used to resolve relative URLs in the HTMLpage_size:one of:a3,:a4,:a5,:b4,:b5,:letter,:legal,:ledger, or{ width:, height:, unit: }margins:one of:none,:normal,:narrow,:moderate,:wide, or{ top:, right:, bottom:, left:, unit: }media:one of:print,:screenresource_fetcher:callable that receives a URL and returnsnilor{ content:, mime_type:, text_encoding: nil }metadata:hash with:title,:author,:subject,:keywords,:creation_date, or:modification_date
metadata[:creation_date] and metadata[:modification_date] should be ISO-8601 strings, for example 2026-05-10T12:00:00Z.
Custom dimensions and margins require unit:. Supported units are :pt, :pc, :in, :cm, :mm, and :px.
- The extension supports writing to a file path with
html_to_pdfor returning PDF bytes withhtml_to_pdf_string. - JavaScript execution is intentionally unsupported.
- Native gems disable PlutoBook's optional curl, TurboJPEG, and WebP features.