Example usage for org.apache.pdfbox.pdmodel.common PDRectangle getLowerLeftY

List of usage examples for org.apache.pdfbox.pdmodel.common PDRectangle getLowerLeftY

Introduction

In this page you can find the example usage for org.apache.pdfbox.pdmodel.common PDRectangle getLowerLeftY.

Prototype

public float getLowerLeftY() 

Source Link

Document

This will get the lower left y coordinate.

Usage

From source file:de.berber.kindle.annotator.lib.Comment.java

License:Apache License

@Override
protected PDAnnotation toPDAnnotation(final @Nonnull PDDocumentOutline documentOutline,
        final @Nonnull PDPage page) {
    LOG.info("Creating annotation " + xPositionFactor + "/" + yPositionFactor + " -> " + text);

    // Create annotation text with background color
    final PDGamma pdColor = getColor();
    final PDAnnotationText textAnnotation = new PDAnnotationText();
    textAnnotation.setContents(getText());
    textAnnotation.setColour(pdColor);//  w w w. j  a  v a 2  s. c om

    // set the text position
    final PDRectangle cropBox = page.getTrimBox();
    final PDRectangle position = new PDRectangle();
    position.setLowerLeftX((float) (cropBox.getLowerLeftX()
            + xPositionFactor * (cropBox.getUpperRightX() - cropBox.getLowerLeftX())));
    position.setUpperRightX((float) (cropBox.getLowerLeftX()
            + xPositionFactor * (cropBox.getUpperRightX() - cropBox.getLowerLeftX())));

    position.setUpperRightY((float) (cropBox.getUpperRightY()
            - yPositionFactor * (cropBox.getUpperRightY() - cropBox.getLowerLeftY())));
    position.setLowerLeftY((float) (cropBox.getUpperRightY()
            - yPositionFactor * (cropBox.getUpperRightY() - cropBox.getLowerLeftY())));

    textAnnotation.setRectangle(position);

    return textAnnotation;
}

From source file:de.berber.kindle.annotator.lib.Marking.java

License:Apache License

@Override
protected PDAnnotation toPDAnnotation(final PDDocumentOutline documentOutline, final PDPage page) {
    LOG.info("Creating marking " + leftXPositionFactor + "/" + lowerYPositionFactor + " -> "
            + rightXPositionFactor + "/" + upperYPositionFactor);

    // create highlighted area
    final PDGamma pdColor = getColor();
    // final PDFont font = PDType1Font.HELVETICA_BOLD;
    // float textHeight = font.getFontHeight("Hg".getBytes(), 0, 2);

    final PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(
            PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
    txtMark.setColour(pdColor);/*  w w w  .jav  a 2 s.  c  o  m*/
    txtMark.setConstantOpacity(opacity);

    if (comment != null) {
        // set comment if available
        txtMark.setContents(comment.getText());
    }

    // Set the rectangle containing the markup
    final PDRectangle cropBox = page.getTrimBox();

    final PDRectangle position = new PDRectangle();
    position.setLowerLeftX((float) (cropBox.getLowerLeftX()
            + leftXPositionFactor * (cropBox.getUpperRightX() - cropBox.getLowerLeftX())));
    position.setUpperRightX((float) (cropBox.getLowerLeftX()
            + rightXPositionFactor * (cropBox.getUpperRightX() - cropBox.getLowerLeftX())));

    position.setLowerLeftY((float) (cropBox.getUpperRightY()
            - (lowerYPositionFactor + ((upperYPositionFactor - lowerYPositionFactor == 0.0) ? 0.025 : 0.00))
                    * (cropBox.getUpperRightY() - cropBox.getLowerLeftY())));
    position.setUpperRightY((float) (cropBox.getUpperRightY()
            - (upperYPositionFactor) * (cropBox.getUpperRightY() - cropBox.getLowerLeftY())));

    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(); // y1
    quads[2] = position.getUpperRightX(); // x2
    quads[3] = position.getUpperRightY(); // y2
    quads[4] = position.getLowerLeftX(); // x3
    quads[5] = position.getLowerLeftY(); // y3
    quads[6] = position.getUpperRightX(); // x4
    quads[7] = position.getLowerLeftY(); // y5

    txtMark.setQuadPoints(quads);

    return txtMark;
}

From source file:helper.pdfpreprocessing.pdf.TextHighlight.java

License:Apache License

private boolean markupMatch(Color color, PDPageContentStream contentStream, Match markingMatch, int height,
        boolean withId, PDPage page, String comment, boolean commentOnly) throws IOException {
    final List<PDRectangle> textBoundingBoxes = getTextBoundingBoxes(markingMatch.positions);

    if (textBoundingBoxes.size() > 0) {
        contentStream.setNonStrokingColor(color);
        for (PDRectangle textBoundingBox : textBoundingBoxes) {
            if (comment.isEmpty()) {
                contentStream.addRect(textBoundingBox.getLowerLeftX(), textBoundingBox.getLowerLeftY(), Math
                        .max(Math.abs(textBoundingBox.getUpperRightX() - textBoundingBox.getLowerLeftX()), 10),
                        height);/*w ww  .ja  v  a  2 s .  com*/
                contentStream.fill();
            }
            if (withId) {
                PDFont font = PDType1Font.HELVETICA;
                contentStream.beginText();
                contentStream.setFont(font, 5);
                contentStream.newLineAtOffset(textBoundingBox.getUpperRightX(),
                        textBoundingBox.getUpperRightY());
                contentStream.showText(markingMatch.str);
                contentStream.endText();
            }
            if (!comment.isEmpty() && !commentOnly) {
                PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(
                        PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
                PDRectangle position = new PDRectangle();
                position.setLowerLeftX(textBoundingBox.getLowerLeftX());
                position.setLowerLeftY(textBoundingBox.getLowerLeftY());
                position.setUpperRightX(textBoundingBox.getLowerLeftX() + Math
                        .max(Math.abs(textBoundingBox.getUpperRightX() - textBoundingBox.getLowerLeftX()), 10));
                position.setUpperRightY(textBoundingBox.getLowerLeftY() + 10);
                txtMark.setRectangle(position);

                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.setConstantOpacity((float) 0.5);
                txtMark.setContents("Missing Assumption/s (" + markingMatch.str + "):\n" + comment);
                float[] colorArray = new float[] { 0, 0, 0 };
                colorArray = color.getColorComponents(colorArray);
                PDColor hColor = new PDColor(colorArray, PDDeviceRGB.INSTANCE);
                txtMark.setColor(hColor);
                txtMark.setCreationDate(Calendar.getInstance());
                txtMark.setTitlePopup("Assumption Error");
                page.getAnnotations().add(txtMark);
            } else if (!comment.isEmpty() && commentOnly) {
                for (int i = 0; i < page.getAnnotations().size(); i++) {
                    String extractedComment = page.getAnnotations().get(i).getContents();
                    if (extractedComment != null) {
                        String commentID = extractedComment.substring(extractedComment.indexOf("(") + 1,
                                extractedComment.indexOf(")"));
                        if (markingMatch.str.equals(commentID) && extractedComment.contains(comment)) {
                            page.getAnnotations().get(i).setContents(extractedComment + "\n" + comment);
                        }

                    }
                }
            }
        }
        return true;
    }
    return false;
}

From source file:hightlighting.PDFTextAnnotator.java

License:Apache License

private float[] computeQuads(PDRectangle rect) {
    float[] quads = new float[8];
    // top left/*  w  w  w . jav a 2s.  com*/
    quads[0] = rect.getLowerLeftX(); // x1
    quads[1] = rect.getUpperRightY(); // y1
    // bottom left
    quads[2] = quads[0]; // x2
    quads[3] = rect.getLowerLeftY(); // y2
    // top right
    quads[4] = rect.getUpperRightX(); // x3
    quads[5] = quads[1]; // y3
    // bottom right
    quads[6] = quads[4]; // x4
    quads[7] = quads[3]; // y5

    return quads;
}

From source file:javaexample.RadialTextPdf.java

License:Open Source License

private void generatePage(PDDocument document) throws IOException {
    // Creates a new page.
    PDPage page = new PDPage(pageRect);
    document.addPage(page);//  w  w w . j  a v a  2s .c om

    // Gets boundings of the page.
    PDRectangle rect = page.getMediaBox();

    // Calculates the side of the square that fits into the page.
    float squareSide = Math.min(rect.getWidth(), rect.getHeight());

    // Calculates the center point of the page.
    float centerX = (rect.getLowerLeftX() + rect.getUpperRightX()) / 2;
    float centerY = (rect.getLowerLeftY() + rect.getUpperRightY()) / 2;

    PDPageContentStream cos = new PDPageContentStream(document, page);

    // Creates the font for the radial text.
    PDFont font = PDType1Font.HELVETICA_BOLD; // Standard font
    float fontSize = squareSide / 30;
    float fontAscent = font.getFontDescriptor().getAscent() / 1000 * fontSize;

    // Calculates key values for the drawings.
    float textX = squareSide / 3.4F; // x of the text.
    float textY = -fontAscent / 2; // y of the text (for vertical centering of text).
    float lineToX = textX * 0.97F; // x destination for the line.
    float lineWidth = squareSide / 900; // width of lines.

    // Moves the origin (0,0) of the axes to the center of the page.
    cos.concatenate2CTM(AffineTransform.getTranslateInstance(centerX, centerY));

    for (float degrees = 0; degrees < 360; degrees += 7.5) {
        double radians = degrees2Radians(degrees);

        // Creates a pure color with the hue based on the angle.
        Color textColor = Color.getHSBColor(degrees / 360.0F, 1, 1);

        // Saves the graphics state because the angle changes on each iteration.
        cos.saveGraphicsState();

        // Rotates the axes by the angle expressed in radians.
        cos.concatenate2CTM(AffineTransform.getRotateInstance(radians));

        // Draws a line from the center of the page.
        cos.setLineWidth(lineWidth);
        cos.moveTo(0, 0);
        cos.lineTo(lineToX, 0);
        cos.stroke();

        // Draws the radial text.
        cos.beginText();
        cos.setNonStrokingColor(textColor);
        cos.setFont(font, fontSize);
        cos.moveTextPositionByAmount(textX, textY);
        cos.drawString("PDF");
        cos.endText();

        // Restores the graphics state to remove rotation transformation.
        cos.restoreGraphicsState();
    }

    cos.close();
}

From source file:org.apache.fop.render.pdf.pdfbox.PDFBoxAdapter.java

License:Apache License

/**
 * Creates a stream (from FOP's PDF library) from a PDF page parsed with PDFBox.
 * @param sourceDoc the source PDF the given page to be copied belongs to
 * @param page the page to transform into a stream
 * @param key value to use as key for the stream
 * @param atdoc adjustment for stream// w w  w .j a v a 2  s  . co  m
 * @param fontinfo fonts
 * @param pos rectangle
 * @return the stream
 * @throws IOException if an I/O error occurs
 */
public String createStreamFromPDFBoxPage(PDDocument sourceDoc, PDPage page, String key, AffineTransform atdoc,
        FontInfo fontinfo, Rectangle pos) throws IOException {
    handleAnnotations(sourceDoc, page, atdoc);
    if (pageNumbers.containsKey(targetPage.getPageIndex())) {
        pageNumbers.get(targetPage.getPageIndex()).set(0, targetPage.makeReference());
    }
    PDResources sourcePageResources = page.getResources();
    PDStream pdStream = getContents(page);

    COSDictionary fonts = (COSDictionary) sourcePageResources.getCOSObject().getDictionaryObject(COSName.FONT);
    COSDictionary fontsBackup = null;
    UniqueName uniqueName = new UniqueName(key, sourcePageResources);
    String newStream = null;
    if (fonts != null && pdfDoc.isMergeFontsEnabled()) {
        fontsBackup = new COSDictionary(fonts);
        MergeFontsPDFWriter m = new MergeFontsPDFWriter(fonts, fontinfo, uniqueName, parentFonts, currentMCID);
        newStream = m.writeText(pdStream);
        //            if (newStream != null) {
        //                for (Object f : fonts.keySet().toArray()) {
        //                    COSDictionary fontdata = (COSDictionary)fonts.getDictionaryObject((COSName)f);
        //                    if (getUniqueFontName(fontdata) != null) {
        //                        fonts.removeItem((COSName)f);
        //                    }
        //                }
        //            }
    }
    if (newStream == null) {
        PDFWriter writer = new PDFWriter(uniqueName, currentMCID);
        newStream = writer.writeText(pdStream);
        currentMCID = writer.getCurrentMCID();

    }
    pdStream = new PDStream(sourceDoc, new ByteArrayInputStream(newStream.getBytes("ISO-8859-1")));
    mergeXObj(sourcePageResources.getCOSObject(), fontinfo, uniqueName);
    PDFDictionary pageResources = (PDFDictionary) cloneForNewDocument(sourcePageResources.getCOSObject());

    PDFDictionary fontDict = (PDFDictionary) pageResources.get("Font");
    if (fontDict != null && pdfDoc.isMergeFontsEnabled()) {
        for (Map.Entry<String, Typeface> fontEntry : fontinfo.getUsedFonts().entrySet()) {
            Typeface font = fontEntry.getValue();
            if (font instanceof FOPPDFFont) {
                FOPPDFFont pdfFont = (FOPPDFFont) font;
                if (pdfFont.getRef() == null) {
                    pdfFont.setRef(new PDFDictionary());
                    pdfDoc.assignObjectNumber(pdfFont.getRef());
                }
                fontDict.put(fontEntry.getKey(), pdfFont.getRef());
            }
        }
    }
    updateXObj(sourcePageResources.getCOSObject(), pageResources);
    if (fontsBackup != null) {
        sourcePageResources.getCOSObject().setItem(COSName.FONT, fontsBackup);
    }

    COSStream originalPageContents = pdStream.getCOSObject();

    bindOptionalContent(sourceDoc);

    PDFStream pageStream;
    Set filter;
    //        if (originalPageContents instanceof COSStreamArray) {
    //            COSStreamArray array = (COSStreamArray)originalPageContents;
    //            pageStream = new PDFStream();
    //            InputStream in = array.getUnfilteredStream();
    //            OutputStream out = pageStream.getBufferOutputStream();
    //            IOUtils.copyLarge(in, out);
    //            filter = FILTER_FILTER;
    //        } else {
    pageStream = (PDFStream) cloneForNewDocument(originalPageContents);
    filter = Collections.EMPTY_SET;
    //        }
    if (pageStream == null) {
        pageStream = new PDFStream();
    }
    if (originalPageContents != null) {
        transferDict(originalPageContents, pageStream, filter);
    }

    transferPageDict(fonts, uniqueName, sourcePageResources);

    PDRectangle mediaBox = page.getMediaBox();
    PDRectangle cropBox = page.getCropBox();
    PDRectangle viewBox = cropBox != null ? cropBox : mediaBox;

    //Handle the /Rotation entry on the page dict
    int rotation = PDFUtil.getNormalizedRotation(page);

    //Transform to FOP's user space
    float w = (float) pos.getWidth() / 1000f;
    float h = (float) pos.getHeight() / 1000f;
    if (rotation == 90 || rotation == 270) {
        float tmp = w;
        w = h;
        h = tmp;
    }
    atdoc.setTransform(AffineTransform.getScaleInstance(w / viewBox.getWidth(), h / viewBox.getHeight()));
    atdoc.translate(0, viewBox.getHeight());
    atdoc.rotate(-Math.PI);
    atdoc.scale(-1, 1);
    atdoc.translate(-viewBox.getLowerLeftX(), -viewBox.getLowerLeftY());

    rotate(rotation, viewBox, atdoc);

    StringBuilder boxStr = new StringBuilder();
    boxStr.append(PDFNumber.doubleOut(mediaBox.getLowerLeftX())).append(' ')
            .append(PDFNumber.doubleOut(mediaBox.getLowerLeftY())).append(' ')
            .append(PDFNumber.doubleOut(mediaBox.getWidth())).append(' ')
            .append(PDFNumber.doubleOut(mediaBox.getHeight())).append(" re W n\n");
    return boxStr.toString() + IOUtils.toString(pdStream.createInputStream(null), "ISO-8859-1");
}

From source file:org.apache.fop.render.pdf.pdfbox.PDFBoxAdapter.java

License:Apache License

private void rotate(int rotation, PDRectangle viewBox, AffineTransform atdoc) {
    float x = viewBox.getWidth() + viewBox.getLowerLeftX();
    float y = viewBox.getHeight() + viewBox.getLowerLeftY();
    switch (rotation) {
    case 90://from   w w  w .  j a v  a 2 s.  c  o m
        atdoc.scale(viewBox.getWidth() / viewBox.getHeight(), viewBox.getHeight() / viewBox.getWidth());
        atdoc.translate(0, viewBox.getWidth());
        atdoc.rotate(-Math.PI / 2.0);
        atdoc.scale(viewBox.getWidth() / viewBox.getHeight(), viewBox.getHeight() / viewBox.getWidth());
        break;
    case 180:
        atdoc.translate(x, y);
        atdoc.rotate(-Math.PI);
        atdoc.translate(-viewBox.getLowerLeftX(), -viewBox.getLowerLeftY());
        break;
    case 270:
        atdoc.translate(viewBox.getLowerLeftX(), y);
        atdoc.rotate(Math.toRadians(270 + 180));
        atdoc.translate(-x, -y);
        break;
    default:
        //no additional transformations necessary
        break;
    }
}

From source file:org.apache.fop.render.pdf.pdfbox.PDFBoxAdapter.java

License:Apache License

private void moveAnnotations(PDPage page, List pageAnnotations, AffineTransform at) {
    PDRectangle mediaBox = page.getMediaBox();
    PDRectangle cropBox = page.getCropBox();
    PDRectangle viewBox = cropBox != null ? cropBox : mediaBox;
    for (Object obj : pageAnnotations) {
        PDAnnotation annot = (PDAnnotation) obj;
        PDRectangle rect = annot.getRectangle();
        float translateX = (float) (at.getTranslateX() - viewBox.getLowerLeftX());
        float translateY = (float) (at.getTranslateY() - viewBox.getLowerLeftY());
        if (rect != null) {
            rect.setUpperRightX(rect.getUpperRightX() + translateX);
            rect.setLowerLeftX(rect.getLowerLeftX() + translateX);
            rect.setUpperRightY(rect.getUpperRightY() + translateY);
            rect.setLowerLeftY(rect.getLowerLeftY() + translateY);
            annot.setRectangle(rect);/* w  w w.  ja v a2s .com*/
        }
        //            COSArray vertices = (COSArray) annot.getCOSObject().getDictionaryObject("Vertices");
        //            if (vertices != null) {
        //                Iterator iter = vertices.iterator();
        //                while (iter.hasNext()) {
        //                    COSFloat x = (COSFloat) iter.next();
        //                    COSFloat y = (COSFloat) iter.next();
        //                    x.setValue(x.floatValue() + translateX);
        //                    y.setValue(y.floatValue() + translateY);
        //                }
        //            }
    }
}

From source file:org.apache.pdflens.views.pagesview.PageDrawer.java

License:Apache License

/**
 * This will draw the page to the requested context.
 *
 * @param g The graphics context to draw onto.
 * @param p The page to draw.//from  www . ja v a2 s .c  o m
 * @param pageDimension The size of the page to draw.
 *
 * @throws IOException If there is an IO error while drawing the page.
 */
public void drawPage(Graphics g, PDPage p, Dimension pageDimension) throws IOException {
    graphics = (Graphics2D) g;
    page = p;
    pageSize = pageDimension;
    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
    // Only if there is some content, we have to process it. 
    // Otherwise we are done here and we will produce an empty page
    if (page.getContents() != null) {
        PDResources resources = page.findResources();
        processStream(page, resources, page.getContents().getStream());
    }
    List annotations = page.getAnnotations();
    for (int i = 0; i < annotations.size(); i++) {
        PDAnnotation annot = (PDAnnotation) annotations.get(i);
        PDRectangle rect = annot.getRectangle();
        String appearanceName = annot.getAppearanceStream();
        PDAppearanceDictionary appearDictionary = annot.getAppearance();
        if (appearDictionary != null) {
            if (appearanceName == null) {
                appearanceName = "default";
            }
            Map appearanceMap = appearDictionary.getNormalAppearance();
            PDAppearanceStream appearance = (PDAppearanceStream) appearanceMap.get(appearanceName);
            if (appearance != null) {
                g.translate((int) rect.getLowerLeftX(), (int) -rect.getLowerLeftY());
                processSubStream(page, appearance.getResources(), appearance.getStream());
                g.translate((int) -rect.getLowerLeftX(), (int) +rect.getLowerLeftY());
            }
        }
    }

}

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

License:Apache License

/**
 * This will create a doucument showing various annotations.
 * /*from  w  ww.j  ava 2s. c o m*/
 * @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();
    }
}