0

I'd like to change zoom level in links in PDF files using iText 7. There are already solutions for legacy iText 5 (1, 2) but there is none for iText 7.

There are many ways links can work (it can be even JavaScript code) but now I'm interested in GoTo actions (i.e. /XYZ, /Fit and others described in ISO 32000-1, Table 151).

My current code locates GoTo actions but I don't know what the destination of a link is (such as page number, coordinates for XYZ zoom type). How do I get the destination of a link? Or am I missing something and that problem can be solved in a different way?

for (int i = 1; i <= numberOfPages; i++) {

    PdfPage page = document.getPage(i);

    List<PdfAnnotation> annots = page.getAnnotations();
    if (annots.isEmpty()) {
        continue;
    }

    for (int j = 0; j < annots.size(); j++) {
        PdfAnnotation annot = annots.get(j);
        if (annot == null) {
            continue;
        }

        PdfDictionary action = annot.getPdfObject()
                .getAsDictionary(PdfName.A);

        if (action == null ||
                !PdfName.GoTo.equals(action.get(PdfName.S))) {
            continue;
        }

        annot.remove(PdfName.A);


        // here I need the destination of action
        int pageNumber = ???
        Rectangle cropBox = document.getPage(pageNumber).getCropBox();

        PdfAction goToAction = PdfAction.createGoTo(PdfExplicitDestination.createXYZ(
                document.getPage(pageNumber), cropBox.getLeft(), cropBox.getTop(), 2F));

        annot.put(PdfName.A, goToAction.getPdfObject());

    }
}

UPDATE Working Code

I managed to deal with GoTo actions - both explicit and of type Named Destination. It works on some pdf file I tested the code against but I'm not sure whether it covers all the possible cases

Note: When dealing with named destination I create explicit destination and then use it instead of named destination. The thing is, however, that named destination still exists in pdf. How do I get rid of it? In iText 5 there was a method consolidateNamedDestinations() which seems to do what I need:

Replaces all the local named links with the actual destinations.

Please see my code:

 try (document) {

    Map<String, PdfObject> namedDests = null;

    for (int i = 1; i <= document.getNumberOfPages(); i++) {

        List<PdfAnnotation> annots = document.getPage(i).getAnnotations();
        if (annots.isEmpty()) {
            continue;
        }

        for (PdfAnnotation annot : annots) {
            if (annot == null) {
                continue;
            }

            PdfDictionary action = annot.getPdfObject()
                    .getAsDictionary(PdfName.A);

            if (action == null) {
                continue;
            }

            PdfName actionType = action.getAsName(PdfName.S);

            if (PdfName.Link.equals(actionType)) {
                throw new UnsupportedOperationException(
                        "Action of type " + action);
            } else if (!PdfName.GoTo.equals(actionType)) {
                continue;
            }

            PdfArray dest = action.getAsArray(PdfName.D);

            // explicit GoTO case
            if (dest != null) {
                changeZoomLevel(document, annot, dest.getAsDictionary(0));
                continue;
            }

            // Named Destination case
            if (namedDests == null) {
                namedDests = document.getCatalog()
                        .getNameTree(PdfName.Dests)
                        .getNames();
            }

            String namedDest = action.getAsString(PdfName.D)
                    .getValue();

            PdfObject d = namedDests.get(namedDest);

            PdfDictionary dict = null;
            if (d instanceof PdfDictionary) {
                PdfArray arr = (PdfArray) ((PdfDictionary) d).get(PdfName.D);
                dict = arr.getAsDictionary(0);
            } else if (d instanceof PdfArray) {
                dict = ((PdfArray) d).getAsDictionary(0);
            }
            changeZoomLevel(document, annot, dict);
        }
    }
}


private static void changeZoomLevel(PdfDocument document,
            PdfAnnotation annot, PdfDictionary dest) {

        annot.remove(PdfName.A);
        annot.put(PdfName.A, createPdfAction(document, dest));
}

private static PdfObject createPdfAction(PdfDocument document, PdfDictionary dest) {
    PdfPage actionPage = document.getPage(dest);

    Rectangle cropBox = actionPage.getCropBox();

    return PdfAction.createGoTo(PdfExplicitDestination.createXYZ(
            actionPage, cropBox.getLeft(), cropBox.getTop(), 1.5F)).getPdfObject();
}
menteith
  • 596
  • 14
  • 51
  • What bout these links https://itextpdf.com/en/resources/examples/itext-7/changing-zoom-factor-link-destination-0 https://itextpdf.com/en/resources/faq/technical-support/itext-7/how-can-i-set-zoom-level-pdf-using-itext-7 – Adam Strauss Dec 02 '19 at 08:58
  • When it comes to first link - I have already dealt with `GoTo` link. Second link shows how `You can use setOpenActionto open a document with a default display magnification level.` This is not I asked for. – menteith Dec 02 '19 at 09:08

0 Answers0