pdf.cr
pdf.cr
A pure Crystal library for PDF generation and parsing.
PDF.cr is a high-performance, pure-Crystal implementation of the PDF 1.7 (ISO 32000-1) specification. It is designed to be a reliable, easy-to-use alternative to C-based libraries like libharu, providing a native Crystal experience for generating and (eventually) parsing PDF documents.
Table of Contents
Background
The motivation behind pdf.cr was to create a PDF generation library for the Crystal ecosystem that doesn't rely on external C dependencies. While libraries like libharu are powerful, they can be difficult to manage in containerized environments or cross-platform builds. By being written in pure Crystal, pdf.cr ensures maximum portability and ease of installation, while leveraging Crystal's performance and type safety.
Install
Add the dependency to your shard.yml:
dependencies:
pdf:
github: watzon/pdf
Then run shards install.
Usage
Quick Start
require "pdf"
# Create a new document
pdf = PDF::Document.new
pdf.title = "My Document"
pdf.author = "Crystal Developer"
# Add a page with content
pdf.page do |page|
page.font "Helvetica-Bold", size: 24
page.text "Hello, World!", at: {72, 720}
page.font "Helvetica", size: 12
page.text "This PDF was generated with pdf.cr", at: {72, 690}
end
# Save to file
pdf.save("output.pdf")
Page Sizes
# Default (US Letter: 612 x 792 points)
pdf.page { |page| }
# Named sizes
pdf.page(size: :a4) { |page| }
pdf.page(size: :legal) { |page| }
pdf.page(size: :tabloid) { |page| }
# Custom size (width x height in points)
pdf.page(width: 400, height: 600) { |page| }
# Landscape orientation
pdf.page(size: :letter, orientation: :landscape) { |page| }
Text
pdf.page do |page|
# Set font (required before drawing text)
page.font "Helvetica", size: 12
# Draw text at position (x, y from bottom-left)
page.text "Hello!", at: {72, 720}
# Change font
page.font "Times-Bold", size: 18
page.text "Bold Times", at: {72, 680}
end
Standard Fonts (Type1)
All 14 standard PDF fonts are built-in:
- Helvetica, Helvetica-Bold, Helvetica-Oblique, Helvetica-BoldOblique
- Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic
- Courier, Courier-Bold, Courier-Oblique, Courier-BoldOblique
- Symbol, ZapfDingbats
TrueType Fonts
Load any TrueType (.ttf) font for full Unicode support:
pdf = PDF::Document.new
# Load a TrueType font
my_font = pdf.load_font("path/to/DejaVuSans.ttf")
pdf.page do |page|
# Use the TrueType font
page.font my_font, size: 16
page.text "English: Hello, World!", at: {72, 720}
page.text "Russian: Привет, мир!", at: {72, 690}
page.text "Greek: Γειά σου, Κόσμε!", at: {72, 660}
page.text "Symbols: © ® ™ € £ ¥ → ←", at: {72, 630}
# You can mix TrueType and Type1 fonts
page.font "Helvetica", size: 12
page.text "Back to Helvetica", at: {72, 590}
end
pdf.save("unicode_text.pdf")
Features:
- Full Unicode support (BMP and supplementary planes)
- Automatic font subsetting (only used glyphs are embedded)
- Proper glyph metrics for accurate text positioning
- ToUnicode mapping for text extraction from generated PDFs
Graphics
pdf.page do |page|
# Set colors (RGB, values 0.0 to 1.0)
page.fill_color(1.0, 0.0, 0.0) # Red fill
page.stroke_color(0.0, 0.0, 1.0) # Blue stroke
# Line width
page.line_width(2)
# Draw a rectangle
page.rectangle(72, 600, 200, 100) # x, y, width, height
page.fill_stroke
# Draw lines
page.move_to(72, 500)
page.line_to(272, 500)
page.stroke
# Graphics state (save/restore)
page.save_graphics_state do
page.fill_color(0.0, 1.0, 0.0)
page.rectangle(100, 400, 50, 50)
page.fill
end
# Original colors are restored here
end
Multiple Pages
pdf = PDF::Document.new
3.times do |i|
pdf.page do |page|
page.font "Helvetica", size: 18
page.text "Page #{i + 1}", at: {72, 720}
end
end
pdf.save("multi_page.pdf")
Getting PDF as Bytes
pdf = PDF::Document.new
pdf.page { |page| page.font("Helvetica", size: 12) }
# Get as Bytes for HTTP response, etc.
bytes = pdf.to_slice
API
PDF::Document
The PDF::Document class is the main entry point for creating and managing PDF files. It handles the document-wide resources, metadata, and page management.
initialize: Creates a new document.page(size, orientation, &block): Adds a new page to the document and yields aPDF::Pageobject.load_font(path): Loads a TrueType font for use in the document.save(path): Serializes the document and writes it to a file.to_slice: Returns the serialized document as aBytesslice.
PDF::Page
The PDF::Page class represents a single page and provides a high-level DSL for drawing content.
font(name_or_font, size): Sets the current font and size.text(string, at): Draws text at the specified coordinates.rectangle(x, y, width, height): Defines a rectangular path.move_to(x, y)/line_to(x, y): Path construction methods.stroke,fill,fill_stroke: Path painting operations.save_graphics_state(&block): Saves the current graphics state, executes the block, and restores it.
Maintainers
Contributing
PRs accepted.
Small note: If editing the README, please conform to the standard-readme specification.
- Fork it (https://github.com/watzon/pdf/fork)
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request
License
MIT © Chris Watson
pdf.cr
- 1
- 0
- 0
- 0
- 3
- about 2 hours ago
- January 19, 2026
MIT License
Mon, 19 Jan 2026 03:24:38 GMT