Pivot PDF

Logo

A PDF creation library written in Rust, designed for SaaS and web applications. Low memory and CPU consumption — even for documents with hundreds of pages.

View the Project on GitHub pivotpdftools/pivot-pdf

Line Graphics

Purpose

Provides basic drawing capabilities for PDF documents: lines, rectangles, paths, fill, stroke, colors, and graphics state management. These are the building blocks for borders, boxes, dividers, charts, and any non-text visual element.

How It Works

Color Model

Colors use the Color struct with RGB components (each 0.0–1.0). Two constructors:

Colors are set independently for stroke and fill operations, matching PDF’s dual-color model.

Drawing Model

PDF uses a path-based drawing model (like PostScript/SVG):

  1. Construct a pathmove_to, line_to, rect, close_path
  2. Paint the pathstroke, fill, or fill_stroke

Paths are not visible until painted. Multiple path segments can be constructed before a single paint operation.

Graphics State

save_state() / restore_state() push/pop the entire graphics state (colors, line width, etc.) on PDF’s internal stack. Use these to isolate style changes so they don’t affect subsequent drawing.

PDF Operator Mapping

Each method appends the corresponding PDF content stream operator:

Method PDF Operator Description
set_stroke_color(Color) r g b RG Set stroke color (RGB)
set_fill_color(Color) r g b rg Set fill color (RGB)
set_line_width(f64) w w Set line width
move_to(x, y) x y m Move current point
line_to(x, y) x y l Line from current point
rect(x, y, w, h) x y w h re Append rectangle
close_path() h Close subpath
stroke() S Stroke path
fill() f Fill path
fill_stroke() B Fill and stroke path
save_state() q Save graphics state
restore_state() Q Restore graphics state

Design Decisions

Usage Examples

use pdf_core::{Color, PdfDocument};

let mut doc = PdfDocument::create("output.pdf").unwrap();
doc.begin_page(612.0, 792.0);

// Stroked rectangle
doc.set_stroke_color(Color::rgb(0.0, 0.0, 0.0));
doc.set_line_width(1.0);
doc.rect(72.0, 72.0, 468.0, 648.0);
doc.stroke();

// Filled rectangle
doc.set_fill_color(Color::gray(0.9));
doc.rect(100.0, 600.0, 200.0, 50.0);
doc.fill();

// Triangle with fill+stroke
doc.save_state();
doc.set_fill_color(Color::rgb(1.0, 0.0, 0.0));
doc.set_stroke_color(Color::rgb(0.0, 0.0, 0.0));
doc.move_to(200.0, 300.0)
    .line_to(300.0, 300.0)
    .line_to(250.0, 400.0)
    .close_path()
    .fill_stroke();
doc.restore_state();

doc.end_document().unwrap();

Limitations & Edge Cases

History of Changes

Issue 9 (2026-02): Initial implementation