---
title: "Adding shape annotations to a PDF document | Nutrient Python SDK"
canonical_url: "https://www.nutrient.io/guides/python/editor/add-shape-annotations-to-pdf/"
md_url: "https://www.nutrient.io/guides/python/editor/add-shape-annotations-to-pdf.md"
last_updated: "2026-06-09T10:32:42.848Z"
description: "How to add shape annotations to a PDF using Nutrient Python SDK."
---

# Adding shape annotations to a PDF document

Use shape annotations to add structured visual markup to PDF files.

Common use cases include:

- Architectural markups

- Diagram and technical drawing tools

- Review workflows with callouts

- Region highlighting and boundary marking

In this guide, you’ll add:

- Lines with configurable ending styles

- Circles and ellipses

- Squares and rectangles

- Custom colors and line widths

[Download sample](https://www.nutrient.io/downloads/samples/python/add-shape-annotations-to-pdf.zip)

## How Nutrient helps

Nutrient Python SDK handles shape annotation structures and rendering.

The SDK handles:

- Parsing shape annotation dictionaries and path construction

- Managing stroke and fill operations with appearance streams

- Handling geometric calculations and coordinate transformations

- Complex line ending styles and cap rendering

## Complete implementation

This example adds multiple shape annotations to a PDF file:

```python

from nutrient_sdk import Document
from nutrient_sdk import PdfEditor
from nutrient_sdk import Color
from nutrient_sdk import PdfLineEndingStyle
from nutrient_sdk import NutrientException

```

## Working with shape annotations

Open the document in a [context manager](https://docs.python.org/3/reference/datamodel.html#context-managers) to ensure cleanup after processing.

Then:

- Create a PDF editor.

- Get the page collection.

- Add a letter-size page (`612 × 792`) if the document is empty.

- Get the annotation collection from the first page.

```python

def main():
    try:
        with Document.open("input.pdf") as document:
            editor = PdfEditor.edit(document)
            pages = editor.page_collection

            if pages.count == 0:
                pages.add(612.0, 792.0)

            page = pages.first
            annotations = page.annotation_collection

```

## Adding a line annotation

Create a line with `add_line(start_x, start_y, end_x, end_y, author, content)`.

This example adds a horizontal line from `(50, 700)` to `(200, 700)`:

By default, the SDK uses:

- Black stroke color (`ARGB 255, 0, 0, 0`)

- `1.0` point line width

```python

            line = annotations.add_line(
                50.0, 700.0, 200.0, 700.0,  # start_x, start_y, end_x, end_y

                "Author",
                "Simple horizontal line"
            )

```

## Adding a line with arrow endings

Create a second line and customize its style.

This example:

- Draws a diagonal line from `(50, 650)` to `(200, 600)`.

- Sets `end_cap` to `PdfLineEndingStyle.CLOSED_ARROW`.

- Sets the color to blue with `Color.from_argb(255, 0, 0, 255)`.

- Sets the line width to `2.0`.

Set ending styles on both `start_cap` and `end_cap`:

```python

            arrow = annotations.add_line(
                50.0, 650.0, 200.0, 600.0,  # start_x, start_y, end_x, end_y

                "Reviewer",
                "Arrow pointing to important area"
            )
            # Optionally customize the line

            arrow.end_cap = PdfLineEndingStyle.CLOSED_ARROW
            arrow.color = Color.from_argb(255, 0, 0, 255)
            arrow.line_width = 2.0

```

Available line ending styles from the `PdfLineEndingStyle` enumeration include:

- `NONE` — No ending (default)

- `SQUARE` — Square ending for boundary indicators

- `CIRCLE` — Circular ending for connection points

- `DIAMOND` — Diamond shape for decision points

- `OPEN_ARROW` — Open arrowhead for directional indicators

- `CLOSED_ARROW` — Filled arrowhead for emphasis

- `BUTT` — Perpendicular line for measurement marks

- `REVERSE_OPEN_ARROW` — Reverse open arrow for backward direction

- `REVERSE_CLOSED_ARROW` — Reverse closed arrow for backward emphasis

- `SLASH` — Slash mark for termination indicators

## Adding a circle annotation

Create a circle with `add_circle(x, y, width, height, author, content)`.

In this sample:

- The bounds are `x=250`, `y=550`, `width=100`, and `height=100`.

- Equal width and height produce a circle.

- Unequal values produce an ellipse.

- The style is updated to green and a `2.0` point line width.

```python

            circle = annotations.add_circle(
                250.0, 550.0, 100.0, 100.0,  # x, y, width, height

                "Editor",
                "Area of interest"
            )
            # Optionally customize the appearance

            circle.color = Color.from_argb(255, 0, 128, 0)
            circle.line_width = 2.0

```

## Adding a square annotation

Create a square or rectangle with `add_square(x, y, width, height, author, content)`.

In this sample:

- The bounds are `x=400`, `y=550`, `width=150`, and `height=100`.

- Equal width and height produce a square.

- Unequal values produce a rectangle.

- The style is updated to purple and a `2.0` point line width.

```python

            square = annotations.add_square(
                400.0, 550.0, 150.0, 100.0,  # x, y, width, height

                "Reviewer",
                "Section to review"
            )
            # Optionally customize the appearance

            square.color = Color.from_argb(255, 128, 0, 128)
            square.line_width = 2.0

```

## Combining multiple shapes

Use consistent styling across multiple shapes to build one markup set.

This sample creates:

- A callout line with an open arrow

- An ellipse highlight

- A rectangular selection box

All three use:

- An orange stroke (`ARGB 255, 255, 165, 0`).

- `1.5` point line width.

```python

            callout_line = annotations.add_line(
                50.0, 500.0, 150.0, 450.0,  # start_x, start_y, end_x, end_y

                "Author", "Callout line"
            )
            callout_line.end_cap = PdfLineEndingStyle.OPEN_ARROW
            callout_line.color = Color.from_argb(255, 255, 165, 0)
            callout_line.line_width = 1.5

            highlight_circle = annotations.add_circle(
                150.0, 420.0, 100.0, 60.0,  # x, y, width, height

                "Author", "Highlighted area"
            )
            highlight_circle.color = Color.from_argb(255, 255, 165, 0)
            highlight_circle.line_width = 1.5

            selection_box = annotations.add_square(
                260.0, 420.0, 100.0, 60.0,  # x, y, width, height

                "Author", "Selection box"
            )
            selection_box.color = Color.from_argb(255, 255, 165, 0)
            selection_box.line_width = 1.5

```

## Saving the document

Save the output PDF and close the editor.

The `except` block catches `NutrientException` if processing fails:

```python

            editor.save_as("output.pdf")
            editor.close()
    except NutrientException as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    main()

```

## Conclusion

Use this workflow to add shape annotations:

1. Open the document using a [context manager](https://docs.python.org/3/reference/datamodel.html#context-managers) for automatic resource cleanup.

2. Create an editor and access the page collection.

3. Ensure at least one page exists by adding a letter-size page if needed.

4. Retrieve the annotation collection from the target page.

5. Create line annotations with `add_line()` specifying start and end coordinates.

6. Customize line endings using `start_cap` and `end_cap` properties with `PdfLineEndingStyle` values.

7. Create circle annotations with `add_circle()` for highlighting regions (equal dimensions create perfect circles).

8. Create square annotations with `add_square()` for boundary marking (equal dimensions create perfect squares).

9. Combine multiple shapes with consistent styling for unified visual markup systems.

10. Save and close the editor.

For related annotation workflows, refer to the [Python SDK annotation guides](https://www.nutrient.io/guides/python/editor.md).
---

## Related pages

- [Adding a custom page to a PDF document](/guides/python/editor/add-custom-page-to-pdf.md)
- [Adding annotations to a PDF document](/guides/python/editor/add-annotations-to-pdf.md)
- [Adding invisible digital signatures to a PDF document](/guides/python/editor/add-invisible-signature-to-pdf.md)
- [Adding interactive form fields to a PDF document](/guides/python/editor/add-form-fields-to-pdf.md)
- [Adding free text annotations to a PDF document](/guides/python/editor/add-freetext-annotations-to-pdf.md)
- [Adding link annotations to a PDF document](/guides/python/editor/add-link-annotations-to-pdf.md)
- [Adding redaction annotations to a PDF document](/guides/python/editor/add-redaction-annotations-to-pdf.md)
- [Adding stamp annotations to a PDF document](/guides/python/editor/add-stamp-annotations-to-pdf.md)
- [Adding sticky note annotations to a PDF document](/guides/python/editor/add-sticky-note-annotations-to-pdf.md)
- [Adding text markup annotations to a PDF document](/guides/python/editor/add-text-markup-annotations-to-pdf.md)
- [Advanced digital signature workflows](/guides/python/editor/advanced-digital-signatures.md)
- [Adding visible digital signatures to a PDF document](/guides/python/editor/add-visible-signature-to-pdf.md)
- [Detecting and adding form fields to a PDF document](/guides/python/editor/detect-and-add-form-fields.md)
- [Editing PDF form fields](/guides/python/editor/editing-pdf-form-fields.md)
- [Editing PDF metadata with Nutrient Python SDK](/guides/python/editor/editing-pdf-metadata.md)
- [Managing PDF page order](/guides/python/editor/manage-pdf-page-order.md)
- [Merging PDFs](/guides/python/editor/merge-pdf-into-other-pdf.md)
- [Nutrient Python SDK editor guides](/guides/python/editor.md)
- [Filling PDF form fields](/guides/python/editor/fill-pdf-form.md)

