Skip to content
Advertisement

How to scale a PDAnnotation?

I have a pdf that has been passed to me with a signature (annotation) and I have to scale the pdf, but when I scale the pdf the annotation does not scale, and it comes out out out of shape. Any suggestions? I’ll show you the code of the method and the pdf before and after

PDF BEFORE

enter image description here

PDF AFTER

enter image description here

Method

    public static byte[] adjustPages(byte[] content) {
    try (PDDocument pdf = PDDocument.load(content)) {
        float letterWidth = PDRectangle.LETTER.getWidth();
        float letterHeight = PDRectangle.LETTER.getHeight();
        PDPageTree tree = pdf.getDocumentCatalog().getPages();
        for (PDPage page : tree) {
            if (page.getMediaBox().getWidth() > letterWidth || page.getMediaBox().getHeight() > letterHeight) {
                float fWidth = letterWidth / page.getMediaBox().getWidth();
                float fHeight = letterHeight / page.getMediaBox().getHeight();
                float factor = Math.min(fWidth, fHeight);

                PDPageContentStream contentStream = new PDPageContentStream(pdf, page, PDPageContentStream.AppendMode.PREPEND, false);
                contentStream.transform(Matrix.getScaleInstance(factor, factor));
                contentStream.close();
                page.setMediaBox(PDRectangle.LETTER);
            }
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        pdf.save(baos);
        return baos.toByteArray();
    }catch (IOException ioe) {
        return content;
    }
}

Advertisement

Answer

As already said in a comment, for each page you should not only scale the content stream but also all other coordinates on it, in particular the rectangles of each annotation thereon. In response you asked for an example.

You can extend your inner if block to

if (page.getMediaBox().getWidth() > letterWidth || page.getMediaBox().getHeight() > letterHeight) {
    float fWidth = letterWidth / page.getMediaBox().getWidth();
    float fHeight = letterHeight / page.getMediaBox().getHeight();
    float factor = Math.min(fWidth, fHeight);

    PDPageContentStream contentStream = new PDPageContentStream(pdf, page, PDPageContentStream.AppendMode.PREPEND, false);
    contentStream.transform(Matrix.getScaleInstance(factor, factor));
    contentStream.close();
    page.setMediaBox(PDRectangle.LETTER);

    for (PDAnnotation pdAnnotation : page.getAnnotations()) {
        PDRectangle rectangle = pdAnnotation.getRectangle();
        PDRectangle scaled = new PDRectangle(factor * rectangle.getLowerLeftX(), factor * rectangle.getLowerLeftY(),
                factor * rectangle.getWidth(), factor * rectangle.getHeight());
        pdAnnotation.setRectangle(scaled);
    }
}

(ScalePageWithAnnots test testForPereZix)

This will scale the rectangular area on the page into which the respective annotation is drawn.

Beware, though: Depending on the exact type of annotations in your documents, you’ll have to scale other properties of the annotations, too.

On one hand there are a number of annotations with some extra coordinate information, e.g. the QuadPoints of link, markup, and redaction annotations.

On the other hand there are annotation properties relevant for a PDF viewer to create an annotation appearance if it does not have an accompanying appearance stream, e.g. border widths of annotations in general and DA font sizes for widgets of text fields.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement