5

Using iText we can easily change zoom level for links. There is even a piece of code that does this for GoTo destination type. For convienence, please find it below.

PdfReader reader = new PdfReader(src);
        PdfDictionary page = reader.getPageN(11);
        PdfArray annots = page.getAsArray(PdfName.ANNOTS); 
        for (int i = 0; i < annots.size(); i++) {
            PdfDictionary annotation = annots.getAsDict(i);
            if (PdfName.LINK.equals(annotation.getAsName(PdfName.SUBTYPE))) {
                PdfArray d = annotation.getAsArray(PdfName.DEST);
                if (d != null && d.size() == 5 && PdfName.XYZ.equals(d.getAsName(1)))
                    d.set(4, new PdfNumber(0));
            }
        }

The code deals only with one of destination types found in PDF files. I'm interested in changing zoom in other types of destinations (they are listed in 32000-1 if anyone wondered). Specifically, I'd like to change each destination to GoTo type and specify my own coordinates. I want left coordinate to be the same as the page height of the page to jump. To do this, I obviously I need the page number. How do I get it?

What have I done so far? The instruction PdfArray d = annotation.getAsArray(PdfName.DEST) gives su an array where its first (0 based) element is page reference and not page number as Bruno Lowagie explains in his iText in Action, 2nd edition, p. 202). The array looks like this:[1931 0 R, /XYZ, 0, 677, 0]`. I cannot find correct command to get page number on my own hence this post.

menteith
  • 596
  • 14
  • 51
  • menteith, could you determine page numbers using the information from Anton's answer? Or are you interested in more example code? Or do you consider your question unanswered in yet another way? – mkl Mar 27 '18 at 08:00
  • Today I'm going to check Anton's suggestion and write some code dealing with page numbering. I will get back to you when I'm done. – menteith Mar 27 '18 at 08:36
  • @mkl Using debugger I've easily found ar array with references ([see](https://i.imgur.com/R0ELrDO.png)) but I have no idea how to get it using iText API. I checked links Anton provided but I find it difficult to understand what should be done. – menteith Mar 27 '18 at 17:13
  • I added an answer with some specific code. – mkl Mar 28 '18 at 10:16
  • Did you mean to say "get a get" in the title? – ryanwebjackson Mar 28 '18 at 18:40

2 Answers2

3

According to this: https://developers.itextpdf.com/fr/node/1750

The first example is an array with two elements 8 0 R and /Fit. The second example is an array with four elements 6 0 R, /XYZ, 0, 806 and 0. You need the first element. It doesn't give you the page number (because there is no such thing as page numbers), but it gives you a reference to the /Page object. Based on that reference, you can deduce the page number by looping over the page tree and comparing the object number of a specific page with the object number in the destination.

And than you can go recursively to extract page number, like this: Extract page number from PDF file

Hope, you find it's helpful. Good luck!

Anton Kot
  • 159
  • 1
  • 5
2

I want left coordinate to be the same as the page height of the page to jump. To do this, I obviously I need the page number. How do I get it?

The assumption that you need the page number is wrong. The PdfReader utility methods mostly work based on page numbers, yes, but there is not much in these methods. If you are ok with some low level data access, therefore, you don't need the page number.

The following is your code with additional code to retrieve the cropbox (which defines left, bottom, right, and top page coordinates), once directly from the object reference you have in your destination and once via page number.

PdfReader reader = new PdfReader(src);
PdfDictionary page = reader.getPageN(11);
PdfArray annots = page.getAsArray(PdfName.ANNOTS); 
for (int i = 0; i < annots.size(); i++) {
    PdfDictionary annotation = annots.getAsDict(i);
    if (PdfName.LINK.equals(annotation.getAsName(PdfName.SUBTYPE))) {
        PdfArray d = annotation.getAsArray(PdfName.DEST);
        if (d == null) {  // in case the link has not a Dest but instead a GoTo action
            PdfDictionary action = annotation.getAsDict(PdfName.A);
            if (action != null)
                d = action.getAsArray(PdfName.D);
        }

        if (d != null && d.size() > 0) {
            System.out.println("Next destination -");
            PdfIndirectReference pageReference = d.getAsIndirectObject(0);

            // Work with target dictionary directly
            PdfDictionary pageDict = d.getAsDict(0);
            PdfArray boxArray = pageDict.getAsArray(PdfName.CROPBOX);
            if (boxArray == null) {
                boxArray = pageDict.getAsArray(PdfName.MEDIABOX);
            }
            Rectangle box = PdfReader.getNormalizedRectangle(boxArray);
            System.out.printf("* Target page object %s has cropbox %s\n", pageReference, box);

            // Work via page number
            for (int pageNr = 1; pageNr <= reader.getNumberOfPages(); pageNr++) {
                PRIndirectReference pp = reader.getPageOrigRef(pageNr);
                if (pp.getGeneration() == pageReference.getGeneration() && pp.getNumber() == pageReference.getNumber()) {
                    System.out.printf("* Target page %s has cropbox %s\n", pageNr, reader.getCropBox(pageNr));
                    break;
                }
            }
        }
    }
}

(ProcessLink test testDetermineTargetPage)


By the way, a destination can also be a named destination. Thus, if the Dest value for some PDFs happens to not be an array but a string, you'll simply have to make a look up in the Dests name tree.

mkl
  • 90,588
  • 15
  • 125
  • 265