You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@pdfbox.apache.org by "Marvin B. Lillehaug" <ma...@gmail.com> on 2013/04/09 11:34:35 UTC

Merge PDFs, add second pdf as child in outline

Hi!
I am trying to create a single pdf from a hierarchy of previously generated
pdfs, and having some problems with the outline.
I have two pdfs, one for the parent and one for its children, and want to
add the existing outline of the children as the child of the existing
outline for the parent.

My current code is
// load pdfs here
PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
pdfMergerUtility.appendDocument(pdf, attachment);

PDDocumentOutline documentOutline =
pdf.getDocumentCatalog().getDocumentOutline();
PDOutlineItem originalRoot = documentOutline.getFirstChild();
PDOutlineItem appendedRoot = originalRoot.getNextSibling();
originalRoot.appendChild(appendedRoot);

//save pdf here

The resulting pdf looks like it is supposed to and the outline is working,
i.e. clicking on a node jumps to the correct page. But the children are
duplicated, they show as both children and siblings of the outline from the
parent pdf.

In all my attempts that resulted in the outline looking like it should,
clicking on the outline nodes had no effect.

Any pointers?

-- 
mvh,
Marvin B. Lillehaug

Re: Merge PDFs, add second pdf as child in outline

Posted by "Marvin B. Lillehaug" <li...@underdusken.no>.
I solved it by doing as in my first post and removing the reference to
outline.Last and outline.firstChild.Next manually:

boolean removeRootOutlineSibling =
pdf.getDocumentCatalog().getDocumentOutline().getFirstChild().getNextSibling()
== null;
pdfMergerUtility.appendDocument(pdf, attachment);

PDDocumentOutline documentOutline =
pdf.getDocumentCatalog().getDocumentOutline();
PDOutlineItem originalRoot = documentOutline.getFirstChild();
PDOutlineItem appendedRoot = originalRoot.getNextSibling();
originalRoot.appendChild(appendedRoot);
if (removeRootOutlineSibling) {
   documentOutline.getCOSDictionary().setItem("Last", originalRoot);
   originalRoot.getCOSDictionary().removeItem(COSName.NEXT);
}

Thanks for the help!

On Tue, Apr 9, 2013 at 1:07 PM, Maruan Sahyoun <sa...@fileaffairs.de> wrote:
> OK - without trying it out :-)
>
> What happens is that as you get the outlines from the attachments and add them to the root of your outlineRoot and overwrite the document catalog the objects the childs are pointing to are not yet part of the document as the actual merging is done afterwards. So you need to rearrange the outline after you have merged the documents.
>
>
> BR
> Maruan Sahyoun
>
> Am 09.04.2013 um 12:48 schrieb "Marvin B. Lillehaug" <ma...@gmail.com>:
>
>> Sorry for being ambiguous.
>>
>> I have two pdfs, A and B that have outlines oA and oB. I want to
>> create a pdf C where the contents are A + B and the outline is oA with
>> oB as the child of oAs first child.
>>
>> oA: RootNode with name A
>> oB: RootNode with name B1
>>      RootNode with name B2
>> oC: RootNode with name A
>>                                        \- Node with name B1
>>                                         \ Node with name B2
>>
>> When using PDFMergerUtility A, B1, and B2 end up as siblings, and
>> clicking on their respective nodes in the resulting pdf works. With
>> the code in my first post it is still possible to click on both
>> instances of the outline items.
>> I have managed to make the outline look the way I want by getting the
>> reference to both roots before doing the merge, and setting this
>> outline before save, but when clicking in the outline nothing happens.
>> Code which accomplish this:
>>
>> PDDocument pdf = PDDocument.load(contentAsPdf);
>>
>> PDDocumentCatalog documentCatalog = pdf.getDocumentCatalog();
>> PDDocumentOutline outline = documentCatalog.getDocumentOutline();
>> PDOutlineItem outlineRoot = outline.getFirstChild();
>>
>> PDDocumentOutline newOutline = new PDDocumentOutline();
>> newOutline.appendChild(outlineRoot);
>>
>> PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
>> PDDocument attachment = PDDocument.load(attachmentsAsPdfs);
>>
>> PDDocumentCatalog attachmentDocumentCatalog = attachment.getDocumentCatalog();
>> PDDocumentOutline attachmentOutline =
>> attachmentDocumentCatalog.getDocumentOutline();
>>
>> PDOutlineItem attachmentOutlineItem = attachmentOutline.getFirstChild();
>>
>> outlineRoot.appendChild(attachmentOutlineItem);
>>
>> documentCatalog.setDocumentOutline(newOutline);
>> attachmentDocumentCatalog.setDocumentOutline(null);
>>
>> pdfMergerUtility.appendDocument(pdf, attachment);
>>
>> pdf.save(new FileOutputStream(contentAsPdf));
>>
>> Do I have to construct a new PDDocument from scratch in order to do this?
>



-- 
mvh,
Marvin B. Lillehaug

Re: Merge PDFs, add second pdf as child in outline

Posted by Maruan Sahyoun <sa...@fileaffairs.de>.
OK - without trying it out :-)

What happens is that as you get the outlines from the attachments and add them to the root of your outlineRoot and overwrite the document catalog the objects the childs are pointing to are not yet part of the document as the actual merging is done afterwards. So you need to rearrange the outline after you have merged the documents.


BR
Maruan Sahyoun

Am 09.04.2013 um 12:48 schrieb "Marvin B. Lillehaug" <ma...@gmail.com>:

> Sorry for being ambiguous.
> 
> I have two pdfs, A and B that have outlines oA and oB. I want to
> create a pdf C where the contents are A + B and the outline is oA with
> oB as the child of oAs first child.
> 
> oA: RootNode with name A
> oB: RootNode with name B1
>      RootNode with name B2
> oC: RootNode with name A
>                                        \- Node with name B1
>                                         \ Node with name B2
> 
> When using PDFMergerUtility A, B1, and B2 end up as siblings, and
> clicking on their respective nodes in the resulting pdf works. With
> the code in my first post it is still possible to click on both
> instances of the outline items.
> I have managed to make the outline look the way I want by getting the
> reference to both roots before doing the merge, and setting this
> outline before save, but when clicking in the outline nothing happens.
> Code which accomplish this:
> 
> PDDocument pdf = PDDocument.load(contentAsPdf);
> 
> PDDocumentCatalog documentCatalog = pdf.getDocumentCatalog();
> PDDocumentOutline outline = documentCatalog.getDocumentOutline();
> PDOutlineItem outlineRoot = outline.getFirstChild();
> 
> PDDocumentOutline newOutline = new PDDocumentOutline();
> newOutline.appendChild(outlineRoot);
> 
> PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
> PDDocument attachment = PDDocument.load(attachmentsAsPdfs);
> 
> PDDocumentCatalog attachmentDocumentCatalog = attachment.getDocumentCatalog();
> PDDocumentOutline attachmentOutline =
> attachmentDocumentCatalog.getDocumentOutline();
> 
> PDOutlineItem attachmentOutlineItem = attachmentOutline.getFirstChild();
> 
> outlineRoot.appendChild(attachmentOutlineItem);
> 
> documentCatalog.setDocumentOutline(newOutline);
> attachmentDocumentCatalog.setDocumentOutline(null);
> 
> pdfMergerUtility.appendDocument(pdf, attachment);
> 
> pdf.save(new FileOutputStream(contentAsPdf));
> 
> Do I have to construct a new PDDocument from scratch in order to do this?


Re: Merge PDFs, add second pdf as child in outline

Posted by "Marvin B. Lillehaug" <ma...@gmail.com>.
Sorry for being ambiguous.

I have two pdfs, A and B that have outlines oA and oB. I want to
create a pdf C where the contents are A + B and the outline is oA with
oB as the child of oAs first child.

oA: RootNode with name A
oB: RootNode with name B1
      RootNode with name B2
oC: RootNode with name A
                                        \- Node with name B1
                                         \ Node with name B2

When using PDFMergerUtility A, B1, and B2 end up as siblings, and
clicking on their respective nodes in the resulting pdf works. With
the code in my first post it is still possible to click on both
instances of the outline items.
I have managed to make the outline look the way I want by getting the
reference to both roots before doing the merge, and setting this
outline before save, but when clicking in the outline nothing happens.
Code which accomplish this:

PDDocument pdf = PDDocument.load(contentAsPdf);

PDDocumentCatalog documentCatalog = pdf.getDocumentCatalog();
PDDocumentOutline outline = documentCatalog.getDocumentOutline();
PDOutlineItem outlineRoot = outline.getFirstChild();

PDDocumentOutline newOutline = new PDDocumentOutline();
newOutline.appendChild(outlineRoot);

PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
PDDocument attachment = PDDocument.load(attachmentsAsPdfs);

PDDocumentCatalog attachmentDocumentCatalog = attachment.getDocumentCatalog();
PDDocumentOutline attachmentOutline =
attachmentDocumentCatalog.getDocumentOutline();

PDOutlineItem attachmentOutlineItem = attachmentOutline.getFirstChild();

outlineRoot.appendChild(attachmentOutlineItem);

documentCatalog.setDocumentOutline(newOutline);
attachmentDocumentCatalog.setDocumentOutline(null);

pdfMergerUtility.appendDocument(pdf, attachment);

pdf.save(new FileOutputStream(contentAsPdf));

Do I have to construct a new PDDocument from scratch in order to do this?

Re: Merge PDFs, add second pdf as child in outline

Posted by Maruan Sahyoun <sa...@fileaffairs.de>.
Hi Marvin,

first I have to say that from your description I didn't fully get what you would like to achieve and which result you get. 

The PDFMergerUtility already appends the outline of your children as a child to the outline of your parent. That's why you get it twice.

From the source:


	PDDocumentOutline destOutline = destCatalog.getDocumentOutline();
        PDDocumentOutline srcOutline = srcCatalog.getDocumentOutline();
        if( srcOutline != null )
        {
            if( destOutline == null )
            {
                PDDocumentOutline cloned =
                    new PDDocumentOutline( (COSDictionary)cloner.cloneForNewDocument( srcOutline ) );
                destCatalog.setDocumentOutline( cloned );
            }
            else
            {
                PDOutlineItem first = srcOutline.getFirstChild();
                if(first != null)
                {
                    PDOutlineItem clonedFirst = new PDOutlineItem(
                            (COSDictionary)cloner.cloneForNewDocument( first ));
                    destOutline.appendChild( clonedFirst );
                }
            }
        }

BR
Maruan Sahyoun

Am 09.04.2013 um 11:34 schrieb Marvin B. Lillehaug <ma...@gmail.com>:

> Hi!
> I am trying to create a single pdf from a hierarchy of previously generated
> pdfs, and having some problems with the outline.
> I have two pdfs, one for the parent and one for its children, and want to
> add the existing outline of the children as the child of the existing
> outline for the parent.
> 
> My current code is
> // load pdfs here
> PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
> pdfMergerUtility.appendDocument(pdf, attachment);
> 
> PDDocumentOutline documentOutline =
> pdf.getDocumentCatalog().getDocumentOutline();
> PDOutlineItem originalRoot = documentOutline.getFirstChild();
> PDOutlineItem appendedRoot = originalRoot.getNextSibling();
> originalRoot.appendChild(appendedRoot);
> 
> //save pdf here
> 
> The resulting pdf looks like it is supposed to and the outline is working,
> i.e. clicking on a node jumps to the correct page. But the children are
> duplicated, they show as both children and siblings of the outline from the
> parent pdf.
> 
> In all my attempts that resulted in the outline looking like it should,
> clicking on the outline nodes had no effect.
> 
> Any pointers?
> 
> -- 
> mvh,
> Marvin B. Lillehaug