Search in sources :

Example 1 with PDDocumentOutline

use of org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline in project pdfbox by apache.

the class PDFMergerUtility method appendDocument.

/**
 * append all pages from source to destination.
 *
 * @param destination the document to receive the pages
 * @param source the document originating the new pages
 *
 * @throws IOException If there is an error accessing data from either
 * document.
 */
public void appendDocument(PDDocument destination, PDDocument source) throws IOException {
    if (source.getDocument().isClosed()) {
        throw new IOException("Error: source PDF is closed.");
    }
    if (destination.getDocument().isClosed()) {
        throw new IOException("Error: destination PDF is closed.");
    }
    PDDocumentCatalog destCatalog = destination.getDocumentCatalog();
    PDDocumentCatalog srcCatalog = source.getDocumentCatalog();
    if (isDynamicXfa(srcCatalog.getAcroForm())) {
        throw new IOException("Error: can't merge source document containing dynamic XFA form content.");
    }
    PDDocumentInformation destInfo = destination.getDocumentInformation();
    PDDocumentInformation srcInfo = source.getDocumentInformation();
    mergeInto(srcInfo.getCOSObject(), destInfo.getCOSObject(), Collections.<COSName>emptySet());
    // use the highest version number for the resulting pdf
    float destVersion = destination.getVersion();
    float srcVersion = source.getVersion();
    if (destVersion < srcVersion) {
        destination.setVersion(srcVersion);
    }
    int pageIndexOpenActionDest = -1;
    if (destCatalog.getOpenAction() == null) {
        // PDFBOX-3972: get local dest page index, it must be reassigned after the page cloning
        PDDestinationOrAction openAction = srcCatalog.getOpenAction();
        PDDestination openActionDestination = null;
        if (openAction instanceof PDActionGoTo) {
            openActionDestination = ((PDActionGoTo) openAction).getDestination();
        } else if (openAction instanceof PDDestination) {
            openActionDestination = (PDDestination) openAction;
        }
        if (openActionDestination instanceof PDPageDestination) {
            PDPage page = ((PDPageDestination) openActionDestination).getPage();
            if (page != null) {
                pageIndexOpenActionDest = srcCatalog.getPages().indexOf(page);
            }
        }
        destCatalog.setOpenAction(srcCatalog.getOpenAction());
    }
    PDFCloneUtility cloner = new PDFCloneUtility(destination);
    mergeAcroForm(cloner, destCatalog, srcCatalog);
    COSArray destThreads = (COSArray) destCatalog.getCOSObject().getDictionaryObject(COSName.THREADS);
    COSArray srcThreads = (COSArray) cloner.cloneForNewDocument(destCatalog.getCOSObject().getDictionaryObject(COSName.THREADS));
    if (destThreads == null) {
        destCatalog.getCOSObject().setItem(COSName.THREADS, srcThreads);
    } else {
        destThreads.addAll(srcThreads);
    }
    PDDocumentNameDictionary destNames = destCatalog.getNames();
    PDDocumentNameDictionary srcNames = srcCatalog.getNames();
    if (srcNames != null) {
        if (destNames == null) {
            destCatalog.getCOSObject().setItem(COSName.NAMES, cloner.cloneForNewDocument(srcNames));
        } else {
            cloner.cloneMerge(srcNames, destNames);
        }
    }
    PDDocumentNameDestinationDictionary destDests = destCatalog.getDests();
    PDDocumentNameDestinationDictionary srcDests = srcCatalog.getDests();
    if (srcDests != null) {
        if (destDests == null) {
            destCatalog.getCOSObject().setItem(COSName.DESTS, cloner.cloneForNewDocument(srcDests));
        } else {
            cloner.cloneMerge(srcDests, destDests);
        }
    }
    PDDocumentOutline destOutline = destCatalog.getDocumentOutline();
    PDDocumentOutline srcOutline = srcCatalog.getDocumentOutline();
    if (srcOutline != null) {
        if (destOutline == null || destOutline.getFirstChild() == null) {
            PDDocumentOutline cloned = new PDDocumentOutline((COSDictionary) cloner.cloneForNewDocument(srcOutline));
            destCatalog.setDocumentOutline(cloned);
        } else {
            // search last sibling for dest, because /Last entry is sometimes wrong
            PDOutlineItem destLastOutlineItem = destOutline.getFirstChild();
            while (destLastOutlineItem.getNextSibling() != null) {
                destLastOutlineItem = destLastOutlineItem.getNextSibling();
            }
            for (PDOutlineItem item : srcOutline.children()) {
                // get each child, clone its dictionary, remove siblings info,
                // append outline item created from there
                COSDictionary clonedDict = (COSDictionary) cloner.cloneForNewDocument(item);
                clonedDict.removeItem(COSName.PREV);
                clonedDict.removeItem(COSName.NEXT);
                PDOutlineItem clonedItem = new PDOutlineItem(clonedDict);
                destLastOutlineItem.insertSiblingAfter(clonedItem);
                destLastOutlineItem = destLastOutlineItem.getNextSibling();
            }
        }
    }
    PageMode destPageMode = destCatalog.getPageMode();
    PageMode srcPageMode = srcCatalog.getPageMode();
    if (destPageMode == null) {
        destCatalog.setPageMode(srcPageMode);
    }
    COSDictionary destLabels = (COSDictionary) destCatalog.getCOSObject().getDictionaryObject(COSName.PAGE_LABELS);
    COSDictionary srcLabels = (COSDictionary) srcCatalog.getCOSObject().getDictionaryObject(COSName.PAGE_LABELS);
    if (srcLabels != null) {
        int destPageCount = destination.getNumberOfPages();
        COSArray destNums;
        if (destLabels == null) {
            destLabels = new COSDictionary();
            destNums = new COSArray();
            destLabels.setItem(COSName.NUMS, destNums);
            destCatalog.getCOSObject().setItem(COSName.PAGE_LABELS, destLabels);
        } else {
            destNums = (COSArray) destLabels.getDictionaryObject(COSName.NUMS);
        }
        COSArray srcNums = (COSArray) srcLabels.getDictionaryObject(COSName.NUMS);
        if (srcNums != null) {
            for (int i = 0; i < srcNums.size(); i += 2) {
                COSNumber labelIndex = (COSNumber) srcNums.getObject(i);
                long labelIndexValue = labelIndex.intValue();
                destNums.add(COSInteger.get(labelIndexValue + destPageCount));
                destNums.add(cloner.cloneForNewDocument(srcNums.getObject(i + 1)));
            }
        }
    }
    COSStream destMetadata = (COSStream) destCatalog.getCOSObject().getDictionaryObject(COSName.METADATA);
    COSStream srcMetadata = (COSStream) srcCatalog.getCOSObject().getDictionaryObject(COSName.METADATA);
    if (destMetadata == null && srcMetadata != null) {
        PDStream newStream = new PDStream(destination, srcMetadata.createInputStream(), (COSName) null);
        mergeInto(srcMetadata, newStream.getCOSObject(), new HashSet<>(Arrays.asList(COSName.FILTER, COSName.LENGTH)));
        destCatalog.getCOSObject().setItem(COSName.METADATA, newStream);
    }
    COSDictionary destOCP = (COSDictionary) destCatalog.getCOSObject().getDictionaryObject(COSName.OCPROPERTIES);
    COSDictionary srcOCP = (COSDictionary) srcCatalog.getCOSObject().getDictionaryObject(COSName.OCPROPERTIES);
    if (destOCP == null && srcOCP != null) {
        destCatalog.getCOSObject().setItem(COSName.OCPROPERTIES, cloner.cloneForNewDocument(srcOCP));
    }
    mergeOutputIntents(cloner, srcCatalog, destCatalog);
    // merge logical structure hierarchy if logical structure information is available in both source pdf and
    // destination pdf
    boolean mergeStructTree = false;
    int destParentTreeNextKey = -1;
    COSDictionary destParentTreeDict = null;
    COSDictionary srcParentTreeDict;
    COSArray destNumbersArray = null;
    COSArray srcNumbersArray = null;
    PDMarkInfo destMark = destCatalog.getMarkInfo();
    PDStructureTreeRoot destStructTree = destCatalog.getStructureTreeRoot();
    PDMarkInfo srcMark = srcCatalog.getMarkInfo();
    PDStructureTreeRoot srcStructTree = srcCatalog.getStructureTreeRoot();
    if (destStructTree != null) {
        PDNumberTreeNode destParentTree = destStructTree.getParentTree();
        destParentTreeNextKey = destStructTree.getParentTreeNextKey();
        if (destParentTree != null) {
            destParentTreeDict = destParentTree.getCOSObject();
            destNumbersArray = (COSArray) destParentTreeDict.getDictionaryObject(COSName.NUMS);
            if (destNumbersArray != null) {
                if (destParentTreeNextKey < 0) {
                    destParentTreeNextKey = destNumbersArray.size() / 2;
                }
                if (destParentTreeNextKey > 0 && srcStructTree != null) {
                    PDNumberTreeNode srcParentTree = srcStructTree.getParentTree();
                    if (srcParentTree != null) {
                        srcParentTreeDict = srcParentTree.getCOSObject();
                        srcNumbersArray = (COSArray) srcParentTreeDict.getDictionaryObject(COSName.NUMS);
                        if (srcNumbersArray != null) {
                            mergeStructTree = true;
                        }
                    }
                }
            }
        }
        if (destMark != null && destMark.isMarked() && !mergeStructTree) {
            destMark.setMarked(false);
        }
        if (!mergeStructTree) {
            destCatalog.setStructureTreeRoot(null);
        }
    }
    Map<COSDictionary, COSDictionary> objMapping = new HashMap<>();
    int pageIndex = 0;
    for (PDPage page : srcCatalog.getPages()) {
        PDPage newPage = new PDPage((COSDictionary) cloner.cloneForNewDocument(page.getCOSObject()));
        newPage.setCropBox(page.getCropBox());
        newPage.setMediaBox(page.getMediaBox());
        newPage.setRotation(page.getRotation());
        PDResources resources = page.getResources();
        if (resources != null) {
            // this is smart enough to just create references for resources that are used on multiple pages
            newPage.setResources(new PDResources((COSDictionary) cloner.cloneForNewDocument(resources)));
        } else {
            newPage.setResources(new PDResources());
        }
        if (mergeStructTree) {
            updateStructParentEntries(newPage, destParentTreeNextKey);
            objMapping.put(page.getCOSObject(), newPage.getCOSObject());
            List<PDAnnotation> oldAnnots = page.getAnnotations();
            List<PDAnnotation> newAnnots = newPage.getAnnotations();
            for (int i = 0; i < oldAnnots.size(); i++) {
                objMapping.put(oldAnnots.get(i).getCOSObject(), newAnnots.get(i).getCOSObject());
            }
        // TODO update mapping for XObjects
        }
        destination.addPage(newPage);
        if (pageIndex == pageIndexOpenActionDest) {
            // PDFBOX-3972: reassign the page.
            // The openAction is either a PDActionGoTo or a PDPageDestination
            PDDestinationOrAction openAction = destCatalog.getOpenAction();
            PDPageDestination pageDestination;
            if (openAction instanceof PDActionGoTo) {
                pageDestination = (PDPageDestination) ((PDActionGoTo) openAction).getDestination();
            } else {
                pageDestination = (PDPageDestination) openAction;
            }
            pageDestination.setPage(newPage);
        }
        ++pageIndex;
    }
    if (mergeStructTree) {
        updatePageReferences(srcNumbersArray, objMapping);
        for (int i = 0; i < srcNumbersArray.size() / 2; i++) {
            destNumbersArray.add(COSInteger.get(destParentTreeNextKey + i));
            destNumbersArray.add(srcNumbersArray.getObject(i * 2 + 1));
        }
        destParentTreeNextKey += srcNumbersArray.size() / 2;
        destParentTreeDict.setItem(COSName.NUMS, destNumbersArray);
        PDNumberTreeNode newParentTreeNode = new PDNumberTreeNode(destParentTreeDict, COSBase.class);
        destStructTree.setParentTree(newParentTreeNode);
        destStructTree.setParentTreeNextKey(destParentTreeNextKey);
        COSDictionary kDictLevel0 = new COSDictionary();
        COSArray newKArray = new COSArray();
        COSArray destKArray = destStructTree.getKArray();
        COSArray srcKArray = srcStructTree.getKArray();
        if (destKArray != null && srcKArray != null) {
            updateParentEntry(destKArray, kDictLevel0);
            newKArray.addAll(destKArray);
            updateParentEntry(srcKArray, kDictLevel0);
            newKArray.addAll(srcKArray);
        }
        kDictLevel0.setItem(COSName.K, newKArray);
        kDictLevel0.setItem(COSName.P, destStructTree);
        kDictLevel0.setItem(COSName.S, COSName.DOCUMENT);
        destStructTree.setK(kDictLevel0);
    }
}
Also used : COSStream(org.apache.pdfbox.cos.COSStream) PDPage(org.apache.pdfbox.pdmodel.PDPage) HashMap(java.util.HashMap) PDDestinationOrAction(org.apache.pdfbox.pdmodel.common.PDDestinationOrAction) PDStructureTreeRoot(org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot) PDPageDestination(org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination) PDMarkInfo(org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo) PDNumberTreeNode(org.apache.pdfbox.pdmodel.common.PDNumberTreeNode) COSArray(org.apache.pdfbox.cos.COSArray) COSNumber(org.apache.pdfbox.cos.COSNumber) PDDocumentInformation(org.apache.pdfbox.pdmodel.PDDocumentInformation) PDActionGoTo(org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo) PDDocumentNameDestinationDictionary(org.apache.pdfbox.pdmodel.PDDocumentNameDestinationDictionary) PageMode(org.apache.pdfbox.pdmodel.PageMode) COSDictionary(org.apache.pdfbox.cos.COSDictionary) PDDocumentOutline(org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline) PDAnnotation(org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation) PDResources(org.apache.pdfbox.pdmodel.PDResources) IOException(java.io.IOException) PDDestination(org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination) PDStream(org.apache.pdfbox.pdmodel.common.PDStream) PDDocumentCatalog(org.apache.pdfbox.pdmodel.PDDocumentCatalog) PDDocumentNameDictionary(org.apache.pdfbox.pdmodel.PDDocumentNameDictionary) PDOutlineItem(org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem)

Example 2 with PDDocumentOutline

use of org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline in project pdfbox by apache.

the class BookmarkValidationProcess method validate.

@Override
public void validate(PreflightContext ctx) throws ValidationException {
    PDDocumentCatalog catalog = ctx.getDocument().getDocumentCatalog();
    if (catalog != null) {
        PDDocumentOutline outlineHierarchy = catalog.getDocumentOutline();
        if (outlineHierarchy != null) {
            COSDictionary dict = outlineHierarchy.getCOSObject();
            if (!checkIndirectObjects(ctx, dict)) {
                return;
            }
            COSObject firstObj = toCOSObject(dict.getItem(COSName.FIRST));
            COSObject lastObj = toCOSObject(dict.getItem(COSName.LAST));
            // Count entry is mandatory if there are childrens
            if (!isCountEntryPresent(dict) && (outlineHierarchy.getFirstChild() != null || outlineHierarchy.getLastChild() != null)) {
                addValidationError(ctx, new ValidationError(ERROR_SYNTAX_TRAILER_OUTLINES_INVALID, "Outline Hierarchy doesn't have Count entry"));
            } else if (isCountEntryPositive(ctx, dict) && (outlineHierarchy.getFirstChild() == null || outlineHierarchy.getLastChild() == null)) {
                addValidationError(ctx, new ValidationError(ERROR_SYNTAX_TRAILER_OUTLINES_INVALID, "Outline Hierarchy doesn't have First and/or Last entry(ies)"));
            } else {
                exploreOutlineLevel(ctx, outlineHierarchy.getFirstChild(), firstObj, lastObj);
            }
        }
    } else {
        ctx.addValidationError(new ValidationError(ERROR_SYNTAX_NOCATALOG, "There is no /Catalog entry in the Document"));
    }
}
Also used : COSDictionary(org.apache.pdfbox.cos.COSDictionary) PDDocumentOutline(org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline) COSObject(org.apache.pdfbox.cos.COSObject) ValidationError(org.apache.pdfbox.preflight.ValidationResult.ValidationError) PDDocumentCatalog(org.apache.pdfbox.pdmodel.PDDocumentCatalog)

Example 3 with PDDocumentOutline

use of org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline in project pdfbox by apache.

the class PrintBookmarks method main.

/**
 * This will print the documents data.
 *
 * @param args The command line arguments.
 *
 * @throws IOException If there is an error parsing the document.
 */
public static void main(String[] args) throws IOException {
    if (args.length != 1) {
        usage();
    } else {
        try (PDDocument document = PDDocument.load(new File(args[0]))) {
            PrintBookmarks meta = new PrintBookmarks();
            PDDocumentOutline outline = document.getDocumentCatalog().getDocumentOutline();
            if (outline != null) {
                meta.printBookmark(document, outline, "");
            } else {
                System.out.println("This document does not contain any bookmarks");
            }
        }
    }
}
Also used : PDDocumentOutline(org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline) PDDocument(org.apache.pdfbox.pdmodel.PDDocument) File(java.io.File)

Example 4 with PDDocumentOutline

use of org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline in project pdfbox by apache.

the class CreateBookmarks method main.

/**
 * This will print the documents data.
 *
 * @param args The command line arguments.
 *
 * @throws IOException If there is an error parsing the document.
 */
public static void main(String[] args) throws IOException {
    if (args.length != 2) {
        usage();
    } else {
        try (PDDocument document = PDDocument.load(new File(args[0]))) {
            if (document.isEncrypted()) {
                System.err.println("Error: Cannot add bookmarks to encrypted document.");
                System.exit(1);
            }
            PDDocumentOutline outline = new PDDocumentOutline();
            document.getDocumentCatalog().setDocumentOutline(outline);
            PDOutlineItem pagesOutline = new PDOutlineItem();
            pagesOutline.setTitle("All Pages");
            outline.addLast(pagesOutline);
            int pageNum = 0;
            for (PDPage page : document.getPages()) {
                pageNum++;
                PDPageDestination dest = new PDPageFitWidthDestination();
                // If you want to have several bookmarks pointing to different areas
                // on the same page, have a look at the other classes derived from PDPageDestination.
                dest.setPage(page);
                PDOutlineItem bookmark = new PDOutlineItem();
                bookmark.setDestination(dest);
                bookmark.setTitle("Page " + pageNum);
                pagesOutline.addLast(bookmark);
            }
            pagesOutline.openNode();
            outline.openNode();
            document.save(args[1]);
        }
    }
}
Also used : PDPageFitWidthDestination(org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageFitWidthDestination) PDPage(org.apache.pdfbox.pdmodel.PDPage) PDDocumentOutline(org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline) PDDocument(org.apache.pdfbox.pdmodel.PDDocument) PDPageDestination(org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination) File(java.io.File) PDOutlineItem(org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem)

Example 5 with PDDocumentOutline

use of org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline in project pdfbox by apache.

the class GoToSecondBookmarkOnOpen method main.

/**
 * This will print the documents data.
 *
 * @param args The command line arguments.
 *
 * @throws IOException If there is an error parsing the document.
 */
public static void main(String[] args) throws IOException {
    if (args.length != 2) {
        usage();
    } else {
        try (PDDocument document = PDDocument.load(new File(args[0]))) {
            if (document.isEncrypted()) {
                System.err.println("Error: Cannot add bookmark destination to encrypted documents.");
                System.exit(1);
            }
            if (document.getNumberOfPages() < 2) {
                throw new IOException("Error: The PDF must have at least 2 pages.");
            }
            PDDocumentOutline bookmarks = document.getDocumentCatalog().getDocumentOutline();
            if (bookmarks == null) {
                throw new IOException("Error: The PDF does not contain any bookmarks");
            }
            PDOutlineItem item = bookmarks.getFirstChild().getNextSibling();
            PDDestination dest = item.getDestination();
            PDActionGoTo action = new PDActionGoTo();
            action.setDestination(dest);
            document.getDocumentCatalog().setOpenAction(action);
            document.save(args[1]);
        }
    }
}
Also used : PDDocumentOutline(org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline) PDDocument(org.apache.pdfbox.pdmodel.PDDocument) IOException(java.io.IOException) PDDestination(org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination) File(java.io.File) PDOutlineItem(org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem) PDActionGoTo(org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo)

Aggregations

PDDocumentOutline (org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline)7 PDOutlineItem (org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem)5 File (java.io.File)4 PDDocument (org.apache.pdfbox.pdmodel.PDDocument)4 IOException (java.io.IOException)2 COSDictionary (org.apache.pdfbox.cos.COSDictionary)2 PDDocumentCatalog (org.apache.pdfbox.pdmodel.PDDocumentCatalog)2 PDPage (org.apache.pdfbox.pdmodel.PDPage)2 PDActionGoTo (org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo)2 PDDestination (org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination)2 PDPageDestination (org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination)2 HashMap (java.util.HashMap)1 COSArray (org.apache.pdfbox.cos.COSArray)1 COSNumber (org.apache.pdfbox.cos.COSNumber)1 COSObject (org.apache.pdfbox.cos.COSObject)1 COSStream (org.apache.pdfbox.cos.COSStream)1 PDDocumentInformation (org.apache.pdfbox.pdmodel.PDDocumentInformation)1 PDDocumentNameDestinationDictionary (org.apache.pdfbox.pdmodel.PDDocumentNameDestinationDictionary)1 PDDocumentNameDictionary (org.apache.pdfbox.pdmodel.PDDocumentNameDictionary)1 PDResources (org.apache.pdfbox.pdmodel.PDResources)1