A PDF generation library for Node.js with comprehensive text, graphics, and form support
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive vector graphics with path construction, shapes, transformations, and painting operations using an HTML5 canvas-like API.
Methods for saving and restoring graphics state for isolated transformations and styling.
/**
* Save current graphics state
* @returns Document instance for chaining
*/
save(): PDFDocument;
/**
* Restore previously saved graphics state
* @returns Document instance for chaining
*/
restore(): PDFDocument;Usage Examples:
// Use save/restore for isolated transformations
doc.save()
.translate(100, 100)
.rotate(45)
.rect(0, 0, 50, 50)
.fill('red')
.restore();
// Continue with original coordinate system
doc.rect(200, 100, 50, 50)
.fill('blue');Low-level path construction methods for creating custom shapes.
/**
* Move to point without drawing
* @param x - X coordinate
* @param y - Y coordinate
* @returns Document instance for chaining
*/
moveTo(x: number, y: number): PDFDocument;
/**
* Draw line to point
* @param x - X coordinate
* @param y - Y coordinate
* @returns Document instance for chaining
*/
lineTo(x: number, y: number): PDFDocument;
/**
* Draw cubic Bezier curve
* @param cp1x - First control point X
* @param cp1y - First control point Y
* @param cp2x - Second control point X
* @param cp2y - Second control point Y
* @param x - End point X
* @param y - End point Y
* @returns Document instance for chaining
*/
bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): PDFDocument;
/**
* Draw quadratic curve
* @param cpx - Control point X
* @param cpy - Control point Y
* @param x - End point X
* @param y - End point Y
* @returns Document instance for chaining
*/
quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): PDFDocument;
/**
* Close current path
* @returns Document instance for chaining
*/
closePath(): PDFDocument;Usage Examples:
// Draw custom shape with path construction
doc.moveTo(100, 100)
.lineTo(200, 150)
.quadraticCurveTo(250, 100, 300, 150)
.lineTo(250, 200)
.closePath()
.fillAndStroke('lightblue', 'navy');
// Complex curve
doc.moveTo(50, 300)
.bezierCurveTo(50, 250, 150, 250, 150, 300)
.bezierCurveTo(150, 350, 50, 350, 50, 300)
.stroke('purple');High-level methods for creating common geometric shapes.
/**
* Draw rectangle
* @param x - X coordinate
* @param y - Y coordinate
* @param w - Width
* @param h - Height
* @returns Document instance for chaining
*/
rect(x: number, y: number, w: number, h: number): PDFDocument;
/**
* Draw rounded rectangle
* @param x - X coordinate
* @param y - Y coordinate
* @param w - Width
* @param h - Height
* @param r - Corner radius
* @returns Document instance for chaining
*/
roundedRect(x: number, y: number, w: number, h: number, r: number): PDFDocument;
/**
* Draw ellipse
* @param x - Center X coordinate
* @param y - Center Y coordinate
* @param r1 - Horizontal radius
* @param r2 - Vertical radius (optional, defaults to r1 for circle)
* @returns Document instance for chaining
*/
ellipse(x: number, y: number, r1: number, r2?: number): PDFDocument;
/**
* Draw circle
* @param x - Center X coordinate
* @param y - Center Y coordinate
* @param radius - Circle radius
* @returns Document instance for chaining
*/
circle(x: number, y: number, radius: number): PDFDocument;
/**
* Draw arc
* @param x - Center X coordinate
* @param y - Center Y coordinate
* @param radius - Arc radius
* @param startAngle - Start angle in radians
* @param endAngle - End angle in radians
* @param anticlockwise - Draw counterclockwise
* @returns Document instance for chaining
*/
arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, anticlockwise?: boolean): PDFDocument;
/**
* Draw polygon from points
* @param points - Array of [x, y] coordinate pairs
* @returns Document instance for chaining
*/
polygon(...points: [number, number][]): PDFDocument;Usage Examples:
// Basic shapes
doc.rect(100, 100, 150, 100)
.fill('lightgreen');
doc.circle(300, 150, 50)
.stroke('red');
doc.roundedRect(100, 250, 150, 100, 10)
.fillAndStroke('yellow', 'orange');
// Ellipse and arc
doc.ellipse(400, 150, 60, 40)
.fill('pink');
doc.arc(200, 400, 50, 0, Math.PI, false)
.stroke('blue');
// Polygon (triangle)
doc.polygon([100, 500], [150, 450], [200, 500])
.fill('purple');Support for rendering SVG path strings.
/**
* Render SVG path string
* @param path - SVG path data string
* @returns Document instance for chaining
*/
path(path: string): PDFDocument;Usage Examples:
// SVG path for complex shape
const heartPath = 'M12,21.35l-1.45-1.32C5.4,15.36,2,12.28,2,8.5 C2,5.42,4.42,3,7.5,3c1.74,0,3.41,0.81,4.5,2.09C13.09,3.81,14.76,3,16.5,3 C19.58,3,22,5.42,22,8.5c0,3.78-3.4,6.86-8.55,11.54L12,21.35z';
doc.save()
.translate(200, 200)
.scale(3)
.path(heartPath)
.fill('red')
.restore();Methods for configuring line appearance and stroke properties.
/**
* Set line width
* @param w - Line width in points
* @returns Document instance for chaining
*/
lineWidth(w: number): PDFDocument;
/**
* Set line cap style
* @param style - Cap style
* @returns Document instance for chaining
*/
lineCap(style: 'BUTT' | 'ROUND' | 'SQUARE' | 0 | 1 | 2): PDFDocument;
/**
* Set line join style
* @param style - Join style
* @returns Document instance for chaining
*/
lineJoin(style: 'MITER' | 'ROUND' | 'BEVEL' | 0 | 1 | 2): PDFDocument;
/**
* Set miter limit for sharp joins
* @param limit - Miter limit
* @returns Document instance for chaining
*/
miterLimit(limit: number): PDFDocument;
/**
* Set dash pattern
* @param length - Dash length or pattern array
* @param options - Dash options
* @returns Document instance for chaining
*/
dash(length: number | number[], options?: DashOptions): PDFDocument;
/**
* Remove dash pattern (solid line)
* @returns Document instance for chaining
*/
undash(): PDFDocument;
interface DashOptions {
/** Phase offset for dash pattern */
phase?: number;
/** Space between dashes */
space?: number;
}Usage Examples:
// Different line styles
doc.lineWidth(5)
.lineCap('round')
.moveTo(100, 100)
.lineTo(200, 100)
.stroke('blue');
doc.lineWidth(3)
.dash(5, { space: 3 })
.rect(100, 150, 100, 50)
.stroke('green');
doc.lineWidth(2)
.dash([10, 5, 2, 5]) // Complex dash pattern
.circle(300, 175, 40)
.stroke('red');
// Remove dash for solid line
doc.undash()
.lineWidth(1)
.rect(100, 250, 100, 50)
.stroke('black');Methods for filling and stroking paths with colors and effects.
/**
* Fill current path
* @param color - Fill color (optional)
* @param rule - Fill rule for complex paths
* @returns Document instance for chaining
*/
fill(color?: ColorValue, rule?: 'nonzero' | 'evenodd'): PDFDocument;
/**
* Stroke current path
* @param color - Stroke color (optional)
* @returns Document instance for chaining
*/
stroke(color?: ColorValue): PDFDocument;
/**
* Fill and stroke current path
* @param fillColor - Fill color (optional)
* @param strokeColor - Stroke color (optional)
* @param rule - Fill rule
* @returns Document instance for chaining
*/
fillAndStroke(fillColor?: ColorValue, strokeColor?: ColorValue, rule?: 'nonzero' | 'evenodd'): PDFDocument;
/**
* Set clipping path
* @param rule - Clipping rule
* @returns Document instance for chaining
*/
clip(rule?: 'nonzero' | 'evenodd'): PDFDocument;
type ColorValue = string | [number, number, number] | [number, number, number, number] | Gradient | Pattern;Usage Examples:
// Different painting operations
doc.rect(100, 100, 100, 50)
.fill('lightblue');
doc.circle(300, 125, 40)
.stroke('red');
doc.roundedRect(100, 200, 100, 50, 5)
.fillAndStroke('yellow', 'orange');
// Using clipping
doc.save()
.circle(200, 300, 50)
.clip()
.rect(150, 250, 100, 100)
.fill('purple')
.restore();Methods for transforming the coordinate system.
/**
* Apply transformation matrix
* @param m11 - Horizontal scaling
* @param m12 - Horizontal skewing
* @param m21 - Vertical skewing
* @param m22 - Vertical scaling
* @param dx - Horizontal translation
* @param dy - Vertical translation
* @returns Document instance for chaining
*/
transform(m11: number, m12: number, m21: number, m22: number, dx: number, dy: number): PDFDocument;
/**
* Translate coordinate system
* @param x - X translation
* @param y - Y translation
* @returns Document instance for chaining
*/
translate(x: number, y: number): PDFDocument;
/**
* Rotate coordinate system
* @param angle - Rotation angle in degrees
* @param options - Rotation options
* @returns Document instance for chaining
*/
rotate(angle: number, options?: RotateOptions): PDFDocument;
/**
* Scale coordinate system
* @param xFactor - Horizontal scale factor
* @param yFactor - Vertical scale factor (optional, defaults to xFactor)
* @param options - Scale options
* @returns Document instance for chaining
*/
scale(xFactor: number, yFactor?: number, options?: TransformOptions): PDFDocument;
interface RotateOptions {
/** Origin point for rotation */
origin?: [number, number];
}
interface TransformOptions {
/** Origin point for transformation */
origin?: [number, number];
}Usage Examples:
// Translation
doc.save()
.translate(200, 200)
.rect(0, 0, 50, 50) // Actually drawn at (200, 200)
.fill('red')
.restore();
// Rotation
doc.save()
.translate(300, 300)
.rotate(45)
.rect(-25, -25, 50, 50) // Rotated square
.fill('blue')
.restore();
// Scale
doc.save()
.translate(400, 200)
.scale(2, 0.5) // 2x width, 0.5x height
.rect(0, 0, 50, 50)
.fill('green')
.restore();
// Complex transformation
doc.save()
.transform(1, 0.5, 0, 1, 100, 400) // Shear transformation
.rect(0, 0, 100, 50)
.fill('purple')
.restore();PDFKit uses a coordinate system where:
For complex self-intersecting paths, PDFKit supports two fill rules:
save()/restore() instead of manual state trackingclip() for masking complex graphicsInstall with Tessl CLI
npx tessl i tessl/npm-pdfkit