[
https://issues.apache.org/jira/browse/PDFBOX-2786?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14527165#comment-14527165
]
Tilman Hausherr edited comment on PDFBOX-2786 at 5/4/15 8:22 PM:
-----------------------------------------------------------------
I doubt whether what you do is correct, see this from the spec:
{quote}
12.3.2.2 Explicit Destinations
Table 151 shows the allowed syntactic forms for specifying a destination
explicitly in a PDF file. In each case, page is an indirect reference to a page
object (except in a remote go-to action; see 12.6.4.3, “Remote Go-To Actions”).
{quote}
So you should put a page object there, not a page number. (Although I tested
with an editor to put page number 1 and it worked). Here's some code that does
what you need:
{code}
COSArray destinationArray = new COSArray();
//destinationArray.add(0,
COSNumber.get(String.valueOf(pagenumber))); // that was your code
destinationArray.add(0,
getPageForFirstBookmark(outline.getFirstChild()).getCOSObject()); // that is new
destinationArray.add(1, COSName.getPDFName("Fit"));
{code}
and here's getPageForFirst Bookmark
{code}
static PDPage getPageForFirstBookmark(PDOutlineItem item) throws IOException
{
if (item != null)
{
PDDestination destination = item.getDestination();
PDAction action = item.getAction();
if (action instanceof PDActionGoTo && destination == null)
{
PDActionGoTo gotoAction = (PDActionGoTo) action;
destination = gotoAction.getDestination();
}
if (destination != null)
{
if (destination instanceof PDPageDestination)
{
PDPageDestination pageDest = (PDPageDestination)
destination;
return pageDest.getPage();
}
}
else
{
return getPageForFirstBookmark(item.getFirstChild());
}
return getPageForFirstBookmark(item.getNextSibling());
}
return null;
}
{code}
and here's a segment from the PDF
{code}
4 0 obj
<<
/Count 2
/First 10 0 R
/Last 11 0 R
/Type /Outlines
>>
endobj
5 0 obj
<<
/Count 2
/Kids [12 0 R 13 0 R]
/Type /Pages
>>
endobj
...
10 0 obj
<<
/A 14 0 R
/Parent 4 0 R
/Title (Page 2)
/Next 11 0 R
>>
endobj
11 0 obj
<<
/Title (Bookmark test)
/A 15 0 R
/Parent 4 0 R
/Prev 10 0 R
>>
endobj
12 0 obj
<<
/Annots [16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R
26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R]
/Contents 32 0 R
/MediaBox [0 0 597.543 834.372]
/Parent 5 0 R
/Resources 33 0 R
/Type /Page
>>
endobj
13 0 obj
<<
/Annots [34 0 R 35 0 R 36 0 R 37 0 R]
/Contents 38 0 R
/MediaBox [0 0 597.543 834.372]
/Parent 5 0 R
/Resources 39 0 R
/Type /Page
>>
endobj
14 0 obj
<<
/D [13 0 R /FitH 1206]
/S /GoTo
>>
endobj
15 0 obj
<<
/S /GoTo
/D [13 0 R /Fit]
>>
endobj
{code}
was (Author: tilman):
I doubt whether what you do is correct, see this from the spec:
{quote}
12.3.2.2 Explicit Destinations
Table 151 shows the allowed syntactic forms for specifying a destination
explicitly in a PDF file. In each case, page is an indirect reference to a page
object (except in a remote go-to action; see 12.6.4.3, “Remote Go-To Actions”).
{quote}
So you should put a page object there, not a page number. (Although I tested
with a page number and it worked). Here's some code that does what you need:
{code}
COSArray destinationArray = new COSArray();
//destinationArray.add(0,
COSNumber.get(String.valueOf(pagenumber))); // that was your code
destinationArray.add(0,
getPageForFirstBookmark(outline.getFirstChild()).getCOSObject()); // that is new
destinationArray.add(1, COSName.getPDFName("Fit"));
{code}
and here's getPageForFirst Bookmark
{code}
static PDPage getPageForFirstBookmark(PDOutlineItem item) throws IOException
{
if (item != null)
{
PDDestination destination = item.getDestination();
PDAction action = item.getAction();
if (action instanceof PDActionGoTo && destination == null)
{
PDActionGoTo gotoAction = (PDActionGoTo) action;
destination = gotoAction.getDestination();
}
if (destination != null)
{
if (destination instanceof PDPageDestination)
{
PDPageDestination pageDest = (PDPageDestination)
destination;
return pageDest.getPage();
}
}
else
{
return getPageForFirstBookmark(item.getFirstChild());
}
return getPageForFirstBookmark(item.getNextSibling());
}
return null;
}
{code}
and here's a segment from the PDF
{code}
4 0 obj
<<
/Count 2
/First 10 0 R
/Last 11 0 R
/Type /Outlines
>>
endobj
5 0 obj
<<
/Count 2
/Kids [12 0 R 13 0 R]
/Type /Pages
>>
endobj
...
10 0 obj
<<
/A 14 0 R
/Parent 4 0 R
/Title (Page 2)
/Next 11 0 R
>>
endobj
11 0 obj
<<
/Title (Bookmark test)
/A 15 0 R
/Parent 4 0 R
/Prev 10 0 R
>>
endobj
12 0 obj
<<
/Annots [16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R
26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R]
/Contents 32 0 R
/MediaBox [0 0 597.543 834.372]
/Parent 5 0 R
/Resources 33 0 R
/Type /Page
>>
endobj
13 0 obj
<<
/Annots [34 0 R 35 0 R 36 0 R 37 0 R]
/Contents 38 0 R
/MediaBox [0 0 597.543 834.372]
/Parent 5 0 R
/Resources 39 0 R
/Type /Page
>>
endobj
14 0 obj
<<
/D [13 0 R /FitH 1206]
/S /GoTo
>>
endobj
15 0 obj
<<
/S /GoTo
/D [13 0 R /Fit]
>>
endobj
{code}
> PDPageDestination page index off by one
> ---------------------------------------
>
> Key: PDFBOX-2786
> URL: https://issues.apache.org/jira/browse/PDFBOX-2786
> Project: PDFBox
> Issue Type: Bug
> Components: PDModel
> Affects Versions: 1.8.9, 2.0.0
> Reporter: Johanneke Lamberink
> Attachments: Archive.zip
>
>
> When creating a new bookmark with the same page number as an existing
> bookmark, the resulting destination is offset by 1 compared to the old
> destination.
> This results in the bookmark being set for the next page, which could be a
> non-existing page.
> I've added a class with an example pdf and my own output pdf. Run with
> argument of a path to where you have the pdf, including a trailing slash.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]