Adding annotations to a PDF document
Adding PDF annotations programmatically enables teams to automate document review workflows, build collaboration tools, and implement markup systems. Whether you’re building document approval systems, implementing automated feedback tools, or creating document annotation platforms, the annotations API provides complete control over annotation types, allowing you to add sticky notes, text markup, stamps, and links, and manage existing annotations without manual PDF editing.
How Nutrient helps you achieve this
Nutrient Java SDK handles PDF annotation structures and appearance stream generation. With the SDK, you don’t need to worry about:
- Parsing annotation dictionaries and appearance streams
- Managing annotation flags and border styles
- Handling coordinate transformations and bounding box calculations
- Complex annotation state management and reply chains
Instead, Nutrient provides an API that handles all the complexity behind the scenes, letting you focus on your business logic.
Complete implementation
Below is a complete working example that demonstrates adding various annotation types to a PDF. The following lines set up the Java application. The package declaration and import statements bring in all necessary classes from the Nutrient SDK:
package io.nutrient.Sample;
import io.nutrient.sdk.Document;import io.nutrient.sdk.types.Color;import io.nutrient.sdk.editors.PdfEditor;import io.nutrient.sdk.editors.pdf.pages.PdfPageCollection;import io.nutrient.sdk.editors.pdf.pages.PdfPage;import io.nutrient.sdk.editors.pdf.annotations.PdfAnnotationCollection;import io.nutrient.sdk.editors.pdf.annotations.PdfAnnotation;import io.nutrient.sdk.editors.pdf.annotations.PdfTextAnnotation;import io.nutrient.sdk.editors.pdf.annotations.PdfHighlightAnnotation;import io.nutrient.sdk.editors.pdf.annotations.PdfUnderlineAnnotation;import io.nutrient.sdk.editors.pdf.annotations.PdfStrikeOutAnnotation;import io.nutrient.sdk.editors.pdf.annotations.PdfSquigglyAnnotation;import io.nutrient.sdk.editors.pdf.annotations.PdfStampAnnotation;import io.nutrient.sdk.editors.pdf.annotations.PdfLinkAnnotation;
public class AddAnnotationsToPdf {The main method defines the entry point that will contain the annotation creation logic:
public static void main(String[] args) {The Document.open() call opens the PDF document. The try-with-resources statement ensures the document is automatically closed when you’re done, preventing resource leaks. The following code creates a PDF editor, accesses the page collection, and ensures at least one page exists by adding a letter-size page if the document is empty:
try (Document document = Document.open("input.pdf")) { PdfEditor editor = PdfEditor.edit(document); PdfPageCollection pages = editor.getPageCollection();
if (pages.getCount() == 0) { pages.add(612.0f, 792.0f); }
PdfPage page = pages.getFirst(); PdfAnnotationCollection annotations = page.getAnnotationCollection();The following code adds a sticky note annotation at coordinates (100, 700) with author metadata, subject, and comment text. After creation, the color is set to yellow using ARGB values (alpha, red, green, blue). Sticky notes are useful for adding comments and review feedback to documents:
PdfTextAnnotation stickyNote = annotations.addStickyNote( 100.0f, 700.0f, // x, y "Test Author", "Test Subject", "This is a sticky note comment" ); // Customize the color stickyNote.setColor(Color.fromArgb(255, 255, 255, 0));The following code blocks add four text markup annotation types: highlight, underline, strikeout, and squiggly. Each annotation is positioned using x, y, width, and height coordinates to define the markup area. The methods accept author and contents parameters for metadata. Colors are customized after creation using ARGB values. These annotations are commonly used for document review workflows to mark text for emphasis, correction, or deletion:
PdfHighlightAnnotation highlight = annotations.addHighlight( 50.0f, 600.0f, 150.0f, 20.0f, // x, y, width, height "Highlighter", "Highlighted text area" ); highlight.setColor(Color.fromArgb(128, 255, 255, 0));
PdfUnderlineAnnotation underline = annotations.addUnderline( 50.0f, 550.0f, 150.0f, 20.0f, // x, y, width, height "Underliner", "Underlined text area" ); underline.setColor(Color.fromArgb(255, 0, 0, 255));
PdfStrikeOutAnnotation strikeOut = annotations.addStrikeOut( 50.0f, 500.0f, 150.0f, 20.0f, // x, y, width, height "Striker", "Struck out text area" ); strikeOut.setColor(Color.fromArgb(255, 255, 0, 0));
PdfSquigglyAnnotation squiggly = annotations.addSquiggly( 50.0f, 450.0f, 150.0f, 20.0f, // x, y, width, height "Squiggler", "Squiggly underlined area" ); squiggly.setColor(Color.fromArgb(255, 0, 128, 0));The following code adds a rubber stamp annotation at coordinates (300, 600) with dimensions 100×50 points. Stamps are created with a default “Draft” style and can be customized with title and contents text. The color is set to purple using ARGB values. Stamp annotations are typically used for approval workflows to indicate document status:
PdfStampAnnotation stamp = annotations.addStamp( 300.0f, 600.0f, 100.0f, 50.0f, // x, y, width, height "Stamp Title", "Stamp contents" ); // Customize the color stamp.setColor(Color.fromArgb(255, 128, 0, 128));The following code demonstrates two types of link annotations. The first creates a clickable area at coordinates (300, 500) that links to an external URI using setURI(). The second adds a new page to the document and creates an internal link that navigates to page 2 at coordinates (0, 792) using setDestination(). Link annotations enable navigation within documents and to external resources:
PdfLinkAnnotation link = annotations.addLink( 300.0f, 500.0f, 200.0f, 20.0f // x, y, width, height ); link.setURI("https://www.nutrient.io");
pages.add(612.0f, 792.0f); PdfLinkAnnotation pageLink = annotations.addLink( 300.0f, 450.0f, 200.0f, 20.0f // x, y, width, height ); pageLink.setDestination(2, 0.0f, 792.0f);The annotation collection supports iteration using a for-each loop, enabling you to examine or process all annotations on a page. The getClass().getSimpleName() method retrieves the annotation type for logging or filtering purposes. The removeAt() method removes an annotation by its zero-based index position. The following code iterates through all annotations, prints their types, removes the first annotation, then saves and closes the editor:
for (PdfAnnotation annot : annotations) { System.out.println("Annotation: " + annot.getClass().getSimpleName()); }
annotations.removeAt(0);
editor.saveAs("output.pdf"); editor.close(); } catch (Exception e) { System.err.println("Error: " + e.getMessage()); e.printStackTrace(); } }}Conclusion
The annotation creation workflow consists of several key operations:
- Open the document and create an editor.
- Access the page collection and ensure at least one page exists.
- Retrieve the annotation collection for the target page.
- Add sticky note annotations with author and comment metadata.
- Add text markup annotations (highlight, underline, strikeout, squiggly) with positioning and colors.
- Add stamp annotations for document status indication.
- Add link annotations for external URIs and internal page navigation.
- Iterate through annotations for processing or filtering.
- Remove annotations by index position.
- Save and close the editor.
Nutrient handles annotation dictionary structures and appearance stream generation so you don’t need to understand PDF annotation specifications or manage coordinate transformations manually.