in pdfbox/src/main/java/org/apache/pdfbox/multipdf/Splitter.java [761:922]
private void processAnnotations(PDPage imported) throws IOException
{
List<PDAnnotation> annotations = imported.getAnnotations();
if (annotations.isEmpty())
{
return;
}
List<PDAnnotation> clonedAnnotations = new ArrayList<>(annotations.size());
for (PDAnnotation annotation : annotations)
{
// create a shallow clone
COSDictionary clonedDict = new COSDictionary(annotation.getCOSObject());
PDAnnotation annotationClone = PDAnnotation.createAnnotation(clonedDict);
annotDictMap.put(annotation.getCOSObject(), clonedDict);
clonedAnnotations.add(annotationClone);
if (annotationClone instanceof PDAnnotationLink)
{
PDAnnotationLink link = (PDAnnotationLink) annotationClone;
PDDestination srcDestination = null;
try
{
srcDestination = link.getDestination();
}
catch (IOException ex)
{
LOG.warn("Incorrect destination in link annotation on page " +
(currentPageNumber + 1) + " is removed", ex);
link.setDestination(null);
}
PDAction action = null;
if (srcDestination == null)
{
action = link.getAction();
if (action instanceof PDActionGoTo)
{
PDActionGoTo goToAction = (PDActionGoTo) action;
try
{
srcDestination = goToAction.getDestination();
}
catch (IOException ex)
{
LOG.warn("GoToAction with incorrect destination in link annotation on page " +
(currentPageNumber + 1) + " is removed", ex);
link.setAction(null);
}
}
}
if (srcDestination instanceof PDNamedDestination)
{
srcDestination = sourceDocument.getDocumentCatalog().
findNamedDestinationPage((PDNamedDestination) srcDestination);
// we do not use the named destination anymore because names get modified, e.g.
// 0xAD becomes 0, see file 410609.pdf where the name no longer matches with the
// entry in the new name tree; plus the original solution was 40 additional loc
}
if (srcDestination instanceof PDPageDestination)
{
// preserve links to pages within the split result:
// not fully possible here because we don't have the full target document yet.
// However we're cloning as needed and remember what to do later.
PDPage destinationPage = ((PDPageDestination) srcDestination).getPage();
if (destinationPage != null)
{
// clone destination
COSArray clonedDestinationArray =
new COSArray(((PDPageDestination) srcDestination).getCOSObject().toList());
PDPageDestination dstDestination =
(PDPageDestination) PDDestination.create(clonedDestinationArray);
// remember the destination to adjust / remove page later
destToFixMap.put(dstDestination, imported);
if (action != null)
{
// if action is not null, then the destination came from an action,
// thus clone action as well, then assign destination clone, then action
COSDictionary clonedActionDict = new COSDictionary(action.getCOSObject());
PDActionGoTo dstAction =
(PDActionGoTo) PDActionFactory.createAction(clonedActionDict);
dstAction.setDestination(dstDestination);
link.setAction(dstAction);
}
else
{
// just assign destination clone
link.setDestination(dstDestination);
}
}
}
}
if (annotationClone instanceof PDAnnotationWidget &&
annotationClone.getCOSObject().containsKey(COSName.PARENT))
{
// remove non-terminal field /Parent reference, because this may lead to orphan pages
annotationClone.getCOSObject().removeItem(COSName.PARENT);
}
if (annotation.getPage() != null)
{
annotationClone.setPage(imported);
}
}
// Second loop for markup and popup annotations, which reference annotations themselves
for (PDAnnotation annotation : clonedAnnotations)
{
if (annotation instanceof PDAnnotationMarkup)
{
PDAnnotationPopup annotationPopup = ((PDAnnotationMarkup) annotation).getPopup();
if (annotationPopup == null)
{
continue;
}
COSDictionary clonedPopupDict = annotDictMap.get(annotationPopup.getCOSObject());
if (clonedPopupDict != null)
{
annotation.getCOSObject().setItem(COSName.POPUP, clonedPopupDict);
}
else
{
// orphan popup (not in annotation list); clone it and fix references
clonedPopupDict = new COSDictionary(annotationPopup.getCOSObject());
annotDictMap.put(annotationPopup.getCOSObject(), clonedPopupDict);
PDAnnotationPopup annotationPopupClone =
(PDAnnotationPopup) PDAnnotation.createAnnotation(clonedPopupDict);
annotationPopupClone.setParent((PDAnnotationMarkup) annotation);
((PDAnnotationMarkup) annotation).setPopup(annotationPopupClone);
if (annotationPopupClone.getPage() != null)
{
annotationPopupClone.setPage(imported);
}
}
}
if (annotation instanceof PDAnnotationPopup)
{
PDAnnotationMarkup annotationMarkup = ((PDAnnotationPopup) annotation).getParent();
if (annotationMarkup == null)
{
continue;
}
COSDictionary clonedMarkupDict = annotDictMap.get(annotationMarkup.getCOSObject());
if (clonedMarkupDict != null)
{
annotation.getCOSObject().setItem(COSName.PARENT, clonedMarkupDict);
}
else
{
// orphan markup (not in annotation list); clone it and fix references
clonedMarkupDict = new COSDictionary(annotationMarkup.getCOSObject());
annotDictMap.put(annotationMarkup.getCOSObject(), clonedMarkupDict);
PDAnnotationMarkup annotationMarkupClone =
(PDAnnotationMarkup) PDAnnotation.createAnnotation(clonedMarkupDict);
annotationMarkupClone.setPopup((PDAnnotationPopup) annotation);
((PDAnnotationPopup) annotation).setParent(annotationMarkupClone);
if (annotationMarkupClone.getPage() != null)
{
annotationMarkupClone.setPage(imported);
}
}
}
}
imported.setAnnotations(clonedAnnotations);
}