Skip to main content

Working with Vector Graphics

PDFDancer allows you to work with vector graphics elements (paths) in PDFs. You can both select existing paths and create new ones - draw lines, shapes, bezier curves, and complex vector graphics.


Selecting Paths

Paths are vector graphics elements in PDFs (lines, shapes, drawings).

from pdfdancer import PDFDancer

with PDFDancer.open("document.pdf") as pdf:
# Get all paths on a specific page
paths = pdf.page(3).select_paths()

# Get paths at specific coordinates
paths_at_point = pdf.page(3).select_paths_at(x=150, y=320)

for path in paths:
print(f"Path ID: {path.internal_id}")

Understanding Vector Paths

Vector paths in PDFs can represent:

  • Lines and curves
  • Shapes (rectangles, circles, polygons)
  • Complex drawings and diagrams
  • Borders and decorative elements

Working with Paths

from pdfdancer import PDFDancer

with PDFDancer.open("document.pdf") as pdf:
# Select paths on a page
paths = pdf.page(1).select_paths()

print(f"Found {len(paths)} paths on page 0")

# You can iterate through paths
for i, path in enumerate(paths):
print(f"Path {i}: {path.internal_id}")

Path Grouping

Group multiple vector paths together and manipulate them as a unit. Path groups support moving, scaling, rotating, resizing, and removing all grouped paths at once.

Creating Path Groups

You can create path groups by specifying explicit path IDs or by selecting all paths within a bounding region.

from pdfdancer import PDFDancer, BoundingRect

with PDFDancer.open("document.pdf") as pdf:
page = pdf.page(1)

# Select paths to group
paths = page.select_paths()
path_ids = [paths[0].internal_id, paths[1].internal_id]

# Group by explicit path IDs
group = page.group_paths(path_ids)

# Or group all paths within a bounding region
region = BoundingRect(x=70, y=710, width=100, height=100)
group = page.group_paths_in_region(region)

print(f"Group contains {group.path_count} paths")

Listing Path Groups

groups = pdf.page(1).get_path_groups()

for group in groups:
print(f"Group {group.group_id}: {group.path_count} paths at ({group.x}, {group.y})")

Manipulating Path Groups

Once grouped, paths can be moved, scaled, rotated, resized, or removed as a unit.

# Move the group to a new position
group.move_to(200.0, 300.0)

# Scale the group by a factor
group.scale(2.0)

# Rotate the group by degrees
group.rotate(90.0)

# Resize the group to specific dimensions
group.resize(50.0, 50.0)

# Remove the group and all its paths
group.remove()

Clearing Path Clipping

Some PDFs use clipping paths to hide vector artwork. If a path or grouped logo is still present in the document model but no longer visible after you move it, clear the inherited clipping before saving.

with PDFDancer.open("document.pdf") as pdf:
page = pdf.page(1)
path = page.select_paths()[0]

# Detach clipping from a single path
path.clear_clipping()

# Detach clipping from a grouped set of paths
group = page.group_paths([path.internal_id])
group.clear_clipping()

pdf.save("output.pdf")

Path Group Properties

PropertyPythonTypeScriptJava
Group IDgroup.group_idgroup.groupIdgroup.getGroupId()
Path countgroup.path_countgroup.pathCountgroup.getPathCount()
Bounding boxgroup.bounding_boxgroup.boundingBoxgroup.getBoundingBox()
X positiongroup.xgroup.xgroup.getX()
Y positiongroup.ygroup.ygroup.getY()

Drawing Lines

Create straight lines on a page:

from pdfdancer import PDFDancer, Color

with PDFDancer.open("document.pdf") as pdf:
page = pdf.page(1)

# Draw a simple line
page.new_line() \
.from_point(100, 100) \
.to_point(400, 100) \
.stroke_color(Color(0, 0, 0)) \
.stroke_width(2) \
.add()

# Draw a dashed line
page.new_line() \
.from_point(100, 150) \
.to_point(400, 150) \
.stroke_color(Color(255, 0, 0)) \
.stroke_width(1) \
.dash_pattern([5, 3]) \
.add()

pdf.save("output.pdf")

Drawing Rectangles

Create rectangles with stroke and fill:

from pdfdancer import PDFDancer, Color

with PDFDancer.open("document.pdf") as pdf:
page = pdf.page(1)

# Draw a stroked rectangle
page.new_rectangle() \
.at_coordinates(100, 200) \
.with_size(200, 100) \
.stroke_color(Color(0, 0, 255)) \
.stroke_width(3) \
.add()

# Draw a filled rectangle
page.new_rectangle() \
.at_coordinates(350, 200) \
.with_size(200, 100) \
.fill_color(Color(255, 200, 0)) \
.add()

# Draw a rectangle with both stroke and fill
page.new_rectangle() \
.at_coordinates(100, 350) \
.with_size(200, 100) \
.stroke_color(Color(0, 0, 0)) \
.stroke_width(2) \
.fill_color(Color(200, 200, 255)) \
.add()

pdf.save("output.pdf")

Drawing Bezier Curves

Create smooth curves using cubic Bezier curves:

from pdfdancer import PDFDancer, Color

with PDFDancer.open("document.pdf") as pdf:
page = pdf.page(1)

# Draw a bezier curve
page.new_bezier() \
.from_point(100, 100) \
.control_point_1(200, 200) \
.control_point_2(300, 200) \
.to_point(400, 100) \
.stroke_color(Color(0, 128, 0)) \
.stroke_width(2) \
.add()

pdf.save("output.pdf")

PathBuilder: Programmatic Path Creation

The newPath() method returns a builder that lets you create complex vector paths programmatically. This builder pattern allows you to chain commands to construct shapes, curves, and complex drawings.

TypeScript PathBuilder Class

In TypeScript SDK v1.0.22+, newPath() returns a PathBuilder instance that provides a fluent API for constructing vector paths. You can also import and use the PathBuilder class directly:

import { PathBuilder } from 'pdfdancer-client-typescript';

Builder Pattern Basics

from pdfdancer import PDFDancer, Color

with PDFDancer.open("document.pdf") as pdf:
# new_path() returns a builder - chain commands and call add()
pdf.page(1).new_path() \
.add_line(Point(100, 100), Point(200, 200)) \
.stroke_color(Color(0, 0, 0)) \
.stroke_width(2) \
.add() # Finalizes and adds the path to the page

Advanced Fill Rules

For complex shapes with overlapping regions, you can control the fill behavior:

// Even-odd fill rule for complex shapes
await pdf.page(1).newPath()
.moveTo(100, 100)
.lineTo(200, 100)
.lineTo(200, 200)
.lineTo(100, 200)
.closePath()
.fillColor(new Color(255, 0, 0))
.evenOddFill(true) // Use even-odd winding rule
.apply();
Even-Odd Fill Rule

The even-odd rule determines whether a point is inside a path by drawing a line from that point to infinity and counting how many times it crosses the path. If the count is odd, the point is inside; if even, it's outside. This is useful for creating shapes with holes or complex overlapping regions.

PathBuilder API Reference

Complete list of PathBuilder methods:

Drawing Commands:

  • moveTo(x, y) - Move to a point without drawing (sets the current point)
  • lineTo(x, y) - Draw a line from current point to (x, y)
  • bezierTo(cp1x, cp1y, cp2x, cp2y, x, y) - Draw a cubic Bezier curve
  • closePath() - Draw a line back to the starting point

Styling:

  • strokeColor(Color) - Set the outline color
  • fillColor(Color) - Set the fill color
  • strokeWidth(number) - Set outline width in points
  • dashPattern([on, off, ...]) - Set dash pattern for strokes

Advanced:

  • dashPhase(number) - Set the offset for dash patterns
  • evenOddFill(boolean) - Use even-odd fill rule (TypeScript)

Finalize:

  • at(pageNumber, x, y) / at(x, y) - Set position and optionally page index
  • add() / apply() - Add the path to the document
Python Method Names

Python uses snake_case: move_to(), line_to(), stroke_color(), etc.


Drawing Complex Paths

Create complex vector graphics using path commands:

from pdfdancer import PDFDancer, Color, Point

with PDFDancer.open("document.pdf") as pdf:
page = pdf.page(1)

# Draw a complex path (triangle)
page.new_path() \
.add_line(Point(250, 100), Point(350, 250)) \
.add_line(Point(350, 250), Point(150, 250)) \
.add_line(Point(150, 250), Point(250, 100)) \
.stroke_color(Color(128, 0, 128)) \
.stroke_width(3) \
.fill_color(Color(255, 200, 255)) \
.add()

# Draw a path with curves
page.new_path() \
.add_line(Point(100, 400), Point(200, 400)) \
.add_bezier(Point(200, 400), Point(250, 450), Point(300, 450), Point(350, 400)) \
.add_line(Point(350, 400), Point(450, 400)) \
.stroke_color(Color(255, 100, 0)) \
.stroke_width(2) \
.add()

pdf.save("output.pdf")

Path Commands

Available path commands:

  • move_to(x, y) / moveTo(x, y) - Move to a point without drawing
  • line_to(x, y) / lineTo(x, y) - Draw a straight line to a point
  • add_bezier(...) / bezierTo(cp1x, cp1y, cp2x, cp2y, x, y) / curveTo(...) - Draw a cubic Bezier curve
  • close_path() / closePath() - Close the current path by drawing a line to the start point

Styling Options

All vector graphics support these styling options:

Stroke (Outline)

  • stroke_color(Color) / strokeColor(Color) - Set the outline color
  • stroke_width(number) / strokeWidth(number) - Set the outline width in points
  • dash_pattern([on, off, ...]) / dashPattern([on, off, ...]) - Create dashed lines

Fill

  • fill_color(Color) / fillColor(Color) - Set the fill color for closed shapes
Stroke vs Fill
  • Use stroke for outlines and lines
  • Use fill for solid shapes
  • Use both for outlined shapes with a fill color
  • Omit both to create invisible paths (useful for clipping regions)

Next Steps