Example usage for org.apache.pdfbox.pdmodel.interactive.annotation PDAnnotationSquareCircle setRectangle

List of usage examples for org.apache.pdfbox.pdmodel.interactive.annotation PDAnnotationSquareCircle setRectangle

Introduction

In this page you can find the example usage for org.apache.pdfbox.pdmodel.interactive.annotation PDAnnotationSquareCircle setRectangle.

Prototype

public void setRectangle(PDRectangle rectangle) 

Source Link

Document

This will set the rectangle for this annotation.

Usage

From source file:airviewer.AnnotationGenerator.java

/**
 * /* ww w .ja va  2  s.c  o  m*/
 * @param document
 * @param page
 * @param subtype
 * @param position
 * @param borderColor
 * @param fillColor
 * @param borderWidth
 * @param contents
 * @return 
 */
public static PDAnnotationMarkup makeAnnotation(PDDocument document, PDPage page, String subtype,
        PDRectangle position, PDColor borderColor, PDColor fillColor, float borderWidth, String contents) {
    assert null != document;
    assert null != page;
    assert null != subtype;
    assert null != position;

    PDAnnotationMarkup result = null;

    try {
        if (null != contents && 0 < contents.length()) {
            PDFont font = FONT;
            final float fontSize = FONT_SIZE_PDF_POINTS;
            final float lineSpacing = LINE_SPACE_SIZE_PDF_POINTS;
            float width = max(position.getWidth(),
                    font.getStringWidth(contents) * fontSize / AnnotationGenerator.SIZE_UNITS_PER_PDF_POINT);
            position.setUpperRightX(position.getLowerLeftX() + width);
        }

        PDAnnotationSquareCircle a = new PDAnnotationSquareCircle(subtype);
        a.setAnnotationName(new UID().toString());
        a.setContents(contents);
        a.setRectangle(position);

        if (null != fillColor) {
            a.setInteriorColor(fillColor);
        }

        if (0 < borderWidth) {
            PDBorderStyleDictionary borderStyle = new PDBorderStyleDictionary();
            borderStyle.setWidth(borderWidth);
            a.setBorderStyle(borderStyle);
            if (null != borderColor) {
                a.setColor(borderColor);

            }
        }

        // The following lines are needed for PDFRenderer to render 
        // annotations. Preview and Acrobat don't seem to need these.
        if (null == a.getAppearance()) {
            a.setAppearance(new PDAppearanceDictionary());
            PDAppearanceStream annotationAppearanceStream = AnnotationGenerator.generateAppearanceStream(a,
                    document, page, true);
            a.getAppearance().setNormalAppearance(annotationAppearanceStream);
        }

        result = a;

    } catch (IOException | NullPointerException ex) {
        Logger.getLogger(EllipseAnnotationMaker.class.getName()).log(Level.SEVERE, null, ex);
    }

    return result;
}

From source file:airviewer.BoxAnnotationMaker.java

License:Apache License

/**
 *
 * @param document/*from   www.ja v  a 2  s  . co m*/
 * @param arguments(lowerLeftX, lowerLeftY, width, height)
 * @return
 */
public static List<PDAnnotation> make(PDDocument document, ArrayList<String> arguments) {
    assert null != arguments && arguments.size() == 5;
    assert null != document;

    List<PDAnnotation> result;

    try {
        int pageNumber = parseInt(arguments.get(0));
        float lowerLeftX = parseFloat(arguments.get(1));
        float lowerLeftY = parseFloat(arguments.get(2));
        float width = parseFloat(arguments.get(3));
        float height = parseFloat(arguments.get(4));
        String contents = "";
        PDFont font = PDType1Font.HELVETICA_OBLIQUE;
        float fontSize = 16; // Or whatever font size you want.
        //float textWidth = font.getStringWidth(contents) * fontSize / 1000.0f;
        //float textHeight = 32;

        try {
            PDPage page = document.getPage(pageNumber);
            PDColor red = new PDColor(new float[] { 1, 0, 0 }, PDDeviceRGB.INSTANCE);
            PDBorderStyleDictionary borderThick = new PDBorderStyleDictionary();
            borderThick.setWidth(72 / 12); // 12th inch
            PDRectangle position = new PDRectangle();
            position.setLowerLeftX(lowerLeftX);
            position.setLowerLeftY(lowerLeftY);
            position.setUpperRightX(lowerLeftX + width);
            position.setUpperRightY(lowerLeftY + height);

            PDAnnotationSquareCircle aSquare = new PDAnnotationSquareCircle(
                    PDAnnotationSquareCircle.SUB_TYPE_SQUARE);
            aSquare.setAnnotationName(new UID().toString());
            aSquare.setContents(contents);
            aSquare.setColor(red); // Outline in red, not setting a fill
            PDColor fillColor = new PDColor(new float[] { .8f, .8f, .8f }, PDDeviceRGB.INSTANCE);
            aSquare.setInteriorColor(fillColor);
            aSquare.setBorderStyle(borderThick);
            aSquare.setRectangle(position);
            result = new ArrayList<>(page.getAnnotations()); // copy
            page.getAnnotations().add(aSquare);

            // The following lines are needed for PDFRenderer to render 
            // annotations. Preview and Acrobat don't seem to need these.
            if (null == aSquare.getAppearance()) {
                aSquare.setAppearance(new PDAppearanceDictionary());
                PDAppearanceStream annotationAppearanceStream = new PDAppearanceStream(document);
                position.setLowerLeftX(lowerLeftX - borderThick.getWidth() * 0.5f);
                position.setLowerLeftY(lowerLeftY - borderThick.getWidth() * 0.5f);
                position.setUpperRightX(lowerLeftX + width + borderThick.getWidth() * 0.5f);
                position.setUpperRightY(lowerLeftY + height + borderThick.getWidth() * 0.5f);
                annotationAppearanceStream.setBBox(position);
                annotationAppearanceStream.setMatrix(new AffineTransform());
                annotationAppearanceStream.setResources(page.getResources());

                try (PDPageContentStream appearanceContent = new PDPageContentStream(document,
                        annotationAppearanceStream)) {
                    Matrix transform = new Matrix();
                    appearanceContent.transform(transform);
                    appearanceContent.addRect(lowerLeftX, lowerLeftY, width, height);
                    appearanceContent.setLineWidth(borderThick.getWidth());
                    appearanceContent.setNonStrokingColor(fillColor);
                    appearanceContent.setStrokingColor(red);
                    appearanceContent.fillAndStroke();
                    appearanceContent.beginText();

                    // Center text vertically, left justified
                    appearanceContent.newLineAtOffset(lowerLeftX, lowerLeftY + height * 0.5f - fontSize * 0.5f);
                    appearanceContent.setFont(font, fontSize);
                    appearanceContent.setNonStrokingColor(red);
                    appearanceContent.showText(contents);
                    appearanceContent.endText();
                }
                aSquare.getAppearance().setNormalAppearance(annotationAppearanceStream);
            }
            //System.out.println(page.getAnnotations().toString());

        } catch (IOException ex) {
            Logger.getLogger(DocumentCommandWrapper.class.getName()).log(Level.SEVERE, null, ex);
            result = null;
        }
    } catch (NumberFormatException | NullPointerException ex) {
        System.err.println("\tNon number encountered where floating point number expected.");
        result = null;
    }

    return result;
}

From source file:airviewer.EllipseAnnotationMaker.java

License:Apache License

/**
 * /*from w  ww.ja v  a 2  s.c o  m*/
 * @param document
 * @param arguments(pageNumber, lowerLeftX, lowerLeftY, width, height, contents)
 * @return 
 */
public static List<PDAnnotation> make(PDDocument document, ArrayList<String> arguments) {
    assert null != arguments && arguments.size() == 6;
    assert null != document;

    List<PDAnnotation> result;

    try {
        int pageNumber = parseInt(arguments.get(0));
        float lowerLeftX = parseFloat(arguments.get(1));
        float lowerLeftY = parseFloat(arguments.get(2));
        float width = parseFloat(arguments.get(3));
        float height = parseFloat(arguments.get(4));
        String contents = arguments.get(5);

        PDFont font = PDType1Font.HELVETICA_OBLIQUE;
        final float fontSize = 16.0f; // Or whatever font size you want.
        //final float lineSpacing = 4.0f;
        width = max(width, font.getStringWidth(contents) * fontSize / 1000.0f);
        //final float textHeight = fontSize + lineSpacing;

        try {
            PDPage page = document.getPage(pageNumber);
            PDColor red = new PDColor(new float[] { 1, 0, 0 }, PDDeviceRGB.INSTANCE);
            PDColor black = new PDColor(new float[] { 0, 0, 0 }, PDDeviceRGB.INSTANCE);
            PDBorderStyleDictionary borderThick = new PDBorderStyleDictionary();
            borderThick.setWidth(72 / 12); // 12th inch
            PDRectangle position = new PDRectangle();
            position.setLowerLeftX(lowerLeftX);
            position.setLowerLeftY(lowerLeftY);
            position.setUpperRightX(lowerLeftX + width);
            position.setUpperRightY(lowerLeftY + height);

            PDAnnotationSquareCircle aCircle = new PDAnnotationSquareCircle(
                    PDAnnotationSquareCircle.SUB_TYPE_CIRCLE);
            aCircle.setAnnotationName(new UID().toString());
            aCircle.setContents(contents);
            PDColor fillColor = new PDColor(new float[] { .8f, .8f, .8f }, PDDeviceRGB.INSTANCE);
            aCircle.setInteriorColor(fillColor);
            aCircle.setColor(red);
            aCircle.setBorderStyle(borderThick);
            aCircle.setRectangle(position);

            result = new ArrayList<>(page.getAnnotations()); // Copy
            page.getAnnotations().add(aCircle);

            // The following lines are needed for PDFRenderer to render 
            // annotations. Preview and Acrobat don't seem to need these.
            if (null == aCircle.getAppearance()) {
                aCircle.setAppearance(new PDAppearanceDictionary());
                PDAppearanceStream annotationAppearanceStream = new PDAppearanceStream(document);
                position.setLowerLeftX(lowerLeftX - borderThick.getWidth() * 0.5f);
                position.setLowerLeftY(lowerLeftY - borderThick.getWidth() * 0.5f);
                position.setUpperRightX(lowerLeftX + width + borderThick.getWidth() * 0.5f);
                position.setUpperRightY(lowerLeftY + height + borderThick.getWidth() * 0.5f);
                annotationAppearanceStream.setBBox(position);
                annotationAppearanceStream.setMatrix(new AffineTransform());
                annotationAppearanceStream.setResources(page.getResources());

                try (PDPageContentStream appearanceContent = new PDPageContentStream(document,
                        annotationAppearanceStream)) {
                    Matrix transform = new Matrix();
                    appearanceContent.transform(transform);
                    appearanceContent.moveTo(lowerLeftX, lowerLeftY + height * 0.5f);
                    appearanceContent.curveTo(lowerLeftX, lowerLeftY + height * 0.75f,
                            lowerLeftX + width * 0.25f, lowerLeftY + height, lowerLeftX + width * 0.5f,
                            lowerLeftY + height);
                    appearanceContent.curveTo(lowerLeftX + width * 0.75f, lowerLeftY + height,
                            lowerLeftX + width, lowerLeftY + height * 0.75f, lowerLeftX + width,
                            lowerLeftY + height * 0.5f);
                    appearanceContent.curveTo(lowerLeftX + width, lowerLeftY + height * 0.25f,
                            lowerLeftX + width * 0.75f, lowerLeftY, lowerLeftX + width * 0.5f, lowerLeftY);
                    appearanceContent.curveTo(lowerLeftX + width * 0.25f, lowerLeftY, lowerLeftX,
                            lowerLeftY + height * 0.25f, lowerLeftX, lowerLeftY + height * 0.5f);
                    appearanceContent.setLineWidth(borderThick.getWidth());
                    appearanceContent.setNonStrokingColor(fillColor);
                    appearanceContent.setStrokingColor(red);
                    appearanceContent.fillAndStroke();
                    appearanceContent.moveTo(0, 0);

                    appearanceContent.beginText();
                    appearanceContent.setNonStrokingColor(black);
                    // Center text vertically, left justified
                    appearanceContent.newLineAtOffset(lowerLeftX + borderThick.getWidth(),
                            lowerLeftY + height * 0.5f - fontSize * 0.5f);
                    appearanceContent.setFont(font, fontSize);
                    appearanceContent.showText(contents);
                    appearanceContent.endText();
                }
                aCircle.getAppearance().setNormalAppearance(annotationAppearanceStream);
            }

        } catch (IOException ex) {
            Logger.getLogger(DocumentCommandWrapper.class.getName()).log(Level.SEVERE, null, ex);
            result = null;
        }
    } catch (NumberFormatException | NullPointerException ex) {
        System.err.println("Non number encountered where floating point number expected.");
        result = null;
    } catch (IOException ex) {
        Logger.getLogger(EllipseAnnotationMaker.class.getName()).log(Level.SEVERE, null, ex);
        result = null;
    }

    return result;
}

From source file:airviewer.TextAnnotationMaker.java

License:Apache License

/**
 * /*from www  .  j av a2s. c o  m*/
 * @param document
 * @param arguments(pageNumber, lowerLeftX, lowerLeftY);
        
    String contents 
 * @return 
 */
public static List<PDAnnotation> make(PDDocument document, ArrayList<String> arguments) {
    assert null != arguments && arguments.size() == 4;
    assert null != document;

    List<PDAnnotation> result;

    try {
        int pageNumber = parseInt(arguments.get(0));
        float lowerLeftX = parseFloat(arguments.get(1));
        float lowerLeftY = parseFloat(arguments.get(2));

        String contents = arguments.get(3);
        PDFont font = PDType1Font.HELVETICA_OBLIQUE;
        final float fontSize = 16.0f; // Or whatever font size you want.
        final float lineSpacing = 4.0f;
        float width = font.getStringWidth(contents) * fontSize / 1000.0f; // font.getStringWidth(contents) returns thousanths of PS point
        final float textHeight = fontSize + lineSpacing;

        try {
            PDPage page = document.getPage(pageNumber);
            PDColor red = new PDColor(new float[] { 1, 0, 0 }, PDDeviceRGB.INSTANCE);
            PDBorderStyleDictionary borderThick = new PDBorderStyleDictionary();
            borderThick.setWidth(72 / 12); // 12th inch
            PDRectangle position = new PDRectangle();
            position.setLowerLeftX(lowerLeftX);
            position.setLowerLeftY(lowerLeftY);
            position.setUpperRightX(lowerLeftX + width);
            position.setUpperRightY(lowerLeftY + textHeight);

            PDAnnotationSquareCircle aSquare = new PDAnnotationSquareCircle(
                    PDAnnotationSquareCircle.SUB_TYPE_SQUARE);
            aSquare.setAnnotationName(new UID().toString());
            aSquare.setContents(contents);
            PDColor fillColor = new PDColor(new float[] { .8f, .8f, .8f }, PDDeviceRGB.INSTANCE);
            aSquare.setInteriorColor(fillColor);
            aSquare.setRectangle(position);
            result = new ArrayList<>(page.getAnnotations()); // copy
            page.getAnnotations().add(aSquare);

            // The following lines are needed for PDFRenderer to render 
            // annotations. Preview and Acrobat don't seem to need these.
            if (null == aSquare.getAppearance()) {
                aSquare.setAppearance(new PDAppearanceDictionary());
                PDAppearanceStream annotationAppearanceStream = new PDAppearanceStream(document);
                position.setLowerLeftX(lowerLeftX - borderThick.getWidth() * 0.5f);
                position.setLowerLeftY(lowerLeftY - borderThick.getWidth() * 0.5f);
                position.setUpperRightX(lowerLeftX + width + borderThick.getWidth() * 0.5f);
                position.setUpperRightY(lowerLeftY + textHeight + borderThick.getWidth() * 0.5f);
                annotationAppearanceStream.setBBox(position);
                annotationAppearanceStream.setMatrix(new AffineTransform());
                annotationAppearanceStream.setResources(page.getResources());

                try (PDPageContentStream appearanceContent = new PDPageContentStream(document,
                        annotationAppearanceStream)) {
                    Matrix transform = new Matrix();
                    appearanceContent.transform(transform);
                    appearanceContent.addRect(lowerLeftX, lowerLeftY, width, textHeight);
                    appearanceContent.setNonStrokingColor(fillColor);
                    appearanceContent.fill();
                    appearanceContent.beginText();

                    // Center text vertically, left justified
                    appearanceContent.newLineAtOffset(lowerLeftX,
                            lowerLeftY + textHeight * 0.5f - fontSize * 0.5f);
                    appearanceContent.setFont(font, fontSize);
                    appearanceContent.setNonStrokingColor(red);
                    appearanceContent.showText(contents);
                    appearanceContent.endText();
                }
                aSquare.getAppearance().setNormalAppearance(annotationAppearanceStream);
            }
            //System.out.println(page.getAnnotations().toString());

        } catch (IOException ex) {
            Logger.getLogger(DocumentCommandWrapper.class.getName()).log(Level.SEVERE, null, ex);
            result = null;
        }
    } catch (NumberFormatException | NullPointerException ex) {
        System.err.println("Non number encountered where floating point number expected.");
        result = null;
    } catch (IOException ex) {
        Logger.getLogger(TextAnnotationMaker.class.getName()).log(Level.SEVERE, null, ex);
        result = null;
    }

    return result;
}

From source file:net.bookinaction.utils.AnnotationMaker.java

License:Apache License

public PDAnnotationSquareCircle squareAnnotation(PDColor color, Rectangle2D.Float position, String message) {

    PDAnnotationSquareCircle aSquare = new PDAnnotationSquareCircle(PDAnnotationSquareCircle.SUB_TYPE_SQUARE);
    aSquare.setContents(message);//w  w  w .j av  a2s. c  om
    aSquare.setColor(color);
    aSquare.setBorderStyle(borderThin);

    aSquare.setRectangle(new PDRectangle(position.x, position.y, position.width, position.height));

    return aSquare;
}

From source file:net.bookinaction.utils.AnnotationMaker.java

License:Apache License

public PDAnnotationSquareCircle circleAnnotation(PDColor fillColor, PDColor lineColor,
        Rectangle2D.Float position, String message) {
    // Now draw a few more annotations
    PDAnnotationSquareCircle aCircle = new PDAnnotationSquareCircle(PDAnnotationSquareCircle.SUB_TYPE_CIRCLE);
    aCircle.setContents(message);/*from   ww  w  .  j  ava2 s. c om*/
    aCircle.setInteriorColor(fillColor); // Fill in circle in red
    aCircle.setColor(lineColor); // The border itself will be blue
    aCircle.setBorderStyle(borderThin);

    aCircle.setRectangle(new PDRectangle(position.x, position.y, position.width, position.height));

    return aCircle;
}

From source file:org.data2semantics.annotate.D2S_SampleAnnotation.java

License:Apache License

/**
 * This will create a doucument showing various annotations.
 * /* w  ww  .  j ava 2s  .c  om*/
 * @param args
 *            The command line arguments.
 * 
 * @throws Exception
 *             If there is an error parsing the document.
 */
public static void main(String[] args) throws Exception {

    PDDocument document = new PDDocument();

    try {
        PDPage page = new PDPage();
        document.addPage(page);
        List annotations = page.getAnnotations();

        // Setup some basic reusable objects/constants
        // Annotations themselves can only be used once!

        float inch = 72;
        PDGamma colourRed = new PDGamma();
        colourRed.setR(1);
        PDGamma colourBlue = new PDGamma();
        colourBlue.setB(1);
        PDGamma colourBlack = new PDGamma();

        PDBorderStyleDictionary borderThick = new PDBorderStyleDictionary();
        borderThick.setWidth(inch / 12); // 12th inch
        PDBorderStyleDictionary borderThin = new PDBorderStyleDictionary();
        borderThin.setWidth(inch / 72); // 1 point
        PDBorderStyleDictionary borderULine = new PDBorderStyleDictionary();
        borderULine.setStyle(PDBorderStyleDictionary.STYLE_UNDERLINE);
        borderULine.setWidth(inch / 72); // 1 point

        float pw = page.getMediaBox().getUpperRightX();
        float ph = page.getMediaBox().getUpperRightY();

        // First add some text, two lines we'll add some annotations to this
        // later

        PDFont font = PDType1Font.HELVETICA_BOLD;

        PDPageContentStream contentStream = new PDPageContentStream(document, page);
        contentStream.beginText();
        contentStream.setFont(font, 18);
        contentStream.moveTextPositionByAmount(inch, ph - inch - 18);
        contentStream.drawString("PDFBox");
        contentStream.moveTextPositionByAmount(0, -(inch / 2));
        contentStream.drawString("Click Here");
        contentStream.endText();

        contentStream.close();

        // Now add the markup annotation, a highlight to PDFBox text
        PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
        txtMark.setColour(colourBlue);
        txtMark.setConstantOpacity((float) 0.2); // Make the highlight 20%
        // transparent

        // Set the rectangle containing the markup

        float textWidth = (font.getStringWidth("PDFBox") / 1000) * 18;
        PDRectangle position = new PDRectangle();
        position.setLowerLeftX(inch);
        position.setLowerLeftY(ph - inch - 18);
        position.setUpperRightX(72 + textWidth);
        position.setUpperRightY(ph - inch);
        txtMark.setRectangle(position);

        // work out the points forming the four corners of the annotations
        // set out in anti clockwise form (Completely wraps the text)
        // OK, the below doesn't match that description.
        // It's what acrobat 7 does and displays properly!
        float[] quads = new float[8];

        quads[0] = position.getLowerLeftX(); // x1
        quads[1] = position.getUpperRightY() - 2; // y1
        quads[2] = position.getUpperRightX(); // x2
        quads[3] = quads[1]; // y2
        quads[4] = quads[0]; // x3
        quads[5] = position.getLowerLeftY() - 2; // y3
        quads[6] = quads[2]; // x4
        quads[7] = quads[5]; // y5

        txtMark.setQuadPoints(quads);
        txtMark.setContents("Highlighted since it's important");

        annotations.add(txtMark);

        // Now add the link annotation, so the clickme works
        PDAnnotationLink txtLink = new PDAnnotationLink();
        txtLink.setBorderStyle(borderULine);

        // Set the rectangle containing the link

        textWidth = (font.getStringWidth("Click Here") / 1000) * 18;
        position = new PDRectangle();
        position.setLowerLeftX(inch);
        position.setLowerLeftY(ph - (float) (1.5 * inch) - 20); // down a
        // couple of
        // points
        position.setUpperRightX(72 + textWidth);
        position.setUpperRightY(ph - (float) (1.5 * inch));
        txtLink.setRectangle(position);

        // add an action
        PDActionURI action = new PDActionURI();
        action.setURI("http://www.pdfbox.org");
        txtLink.setAction(action);

        annotations.add(txtLink);

        // Now draw a few more annotations

        PDAnnotationSquareCircle aCircle = new PDAnnotationSquareCircle(
                PDAnnotationSquareCircle.SUB_TYPE_CIRCLE);
        aCircle.setContents("Circle Annotation");
        aCircle.setInteriorColour(colourRed); // Fill in circle in red
        aCircle.setColour(colourBlue); // The border itself will be blue
        aCircle.setBorderStyle(borderThin);

        // Place the annotation on the page, we'll make this 1" round
        // 3" down, 1" in on the page

        position = new PDRectangle();
        position.setLowerLeftX(inch);
        position.setLowerLeftY(ph - (3 * inch) - inch); // 1" height, 3"
        // down
        position.setUpperRightX(2 * inch); // 1" in, 1" width
        position.setUpperRightY(ph - (3 * inch)); // 3" down
        aCircle.setRectangle(position);

        // add to the annotations on the page
        annotations.add(aCircle);

        // Now a square annotation

        PDAnnotationSquareCircle aSquare = new PDAnnotationSquareCircle(
                PDAnnotationSquareCircle.SUB_TYPE_SQUARE);
        aSquare.setContents("Square Annotation");
        aSquare.setColour(colourRed); // Outline in red, not setting a fill
        aSquare.setBorderStyle(borderThick);

        // Place the annotation on the page, we'll make this 1" (72points)
        // square
        // 3.5" down, 1" in from the right on the page

        position = new PDRectangle(); // Reuse the variable, but note it's a
        // new object!
        position.setLowerLeftX(pw - (2 * inch)); // 1" in from right, 1"
        // wide
        position.setLowerLeftY(ph - (float) (3.5 * inch) - inch); // 1" height, 3.5"
        // down
        position.setUpperRightX(pw - inch); // 1" in from right
        position.setUpperRightY(ph - (float) (3.5 * inch)); // 3.5" down
        aSquare.setRectangle(position);

        // add to the annotations on the page
        annotations.add(aSquare);

        // Now we want to draw a line between the two, one end with an open
        // arrow

        PDAnnotationLine aLine = new PDAnnotationLine();

        aLine.setEndPointEndingStyle(PDAnnotationLine.LE_OPEN_ARROW);
        aLine.setContents("Circle->Square");
        aLine.setCaption(true); // Make the contents a caption on the line

        // Set the rectangle containing the line

        position = new PDRectangle(); // Reuse the variable, but note it's a
        // new object!
        position.setLowerLeftX(2 * inch); // 1" in + width of circle
        position.setLowerLeftY(ph - (float) (3.5 * inch) - inch); // 1" height, 3.5"
        // down
        position.setUpperRightX(pw - inch - inch); // 1" in from right, and
        // width of square
        position.setUpperRightY(ph - (3 * inch)); // 3" down (top of circle)
        aLine.setRectangle(position);

        // Now set the line position itself
        float[] linepos = new float[4];
        linepos[0] = 2 * inch; // x1 = rhs of circle
        linepos[1] = ph - (float) (3.5 * inch); // y1 halfway down circle
        linepos[2] = pw - (2 * inch); // x2 = lhs of square
        linepos[3] = ph - (4 * inch); // y2 halfway down square
        aLine.setLine(linepos);

        aLine.setBorderStyle(borderThick);
        aLine.setColour(colourBlack);

        // add to the annotations on the page
        annotations.add(aLine);

        // Finally all done

        document.save("testAnnotation.pdf");
    } finally {
        document.close();
    }
}