in src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java [479:551]
private void handleAnnotations(PDDocument sourceDoc, PDPage page, AffineTransform at, Rectangle pos)
throws IOException {
PDDocumentCatalog srcCatalog = sourceDoc.getDocumentCatalog();
PDAcroForm srcAcroForm = srcCatalog.getAcroForm();
List pageAnnotations = page.getAnnotations();
if (srcAcroForm == null && pageAnnotations.isEmpty()) {
return;
}
PDFBoxAdapterUtil.moveAnnotations(page, pageAnnotations, at, pos);
//Pseudo-cache the target page in place of the original source page.
//This essentially replaces the original page reference with the target page.
COSObject cosPage = null;
COSDictionary parentDic = (COSDictionary) page.getCOSObject().getDictionaryObject(COSName.PARENT, COSName.P);
COSArray kids = (COSArray) parentDic.getDictionaryObject(COSName.KIDS);
for (int i = 0; i < kids.size(); i++) {
//Hopefully safe to cast, as kids need to be indirect objects
COSObject kid = (COSObject) kids.get(i);
if (!pageNumbers.containsKey(i)) {
PDFArray a = new PDFArray();
a.add(null);
pdfDoc.assignObjectNumber(a);
pdfDoc.addTrailerObject(a);
pageNumbers.put(i, a);
}
cacheClonedObject(kid, pageNumbers.get(i));
if (kid.getObject() == page.getCOSObject()) {
cosPage = kid;
}
}
if (cosPage == null) {
throw new IOException("Illegal PDF. Page not part of parent page node.");
}
Set<?> fields = copyAnnotations(page, srcAcroForm);
boolean formAlreadyCopied = getCachedClone(srcAcroForm) != null;
PDFRoot catalog = this.pdfDoc.getRoot();
PDFDictionary destAcroForm = (PDFDictionary)catalog.get(COSName.ACRO_FORM.getName());
if (formAlreadyCopied) {
//skip, already copied
} else if (destAcroForm == null) {
if (srcAcroForm != null) {
//With this, only the first PDF's AcroForm is copied over. If later AcroForms have
//different properties besides the actual fields, these get lost. Only fields
//get merged.
Collection exclude = Collections.singletonList(COSName.FIELDS);
destAcroForm = (PDFDictionary)cloneForNewDocument(srcAcroForm, srcAcroForm, exclude);
} else {
//Work-around for incorrectly split PDFs which lack an AcroForm but have widgets
//on pages. This doesn't handle the case where field dicts have "C" entries
//(for the "CO" entry), so this may produce problems, but we have almost no chance
//to guess the calculation order.
destAcroForm = new PDFDictionary(pdfDoc.getRoot());
}
pdfDoc.assignObjectNumber(destAcroForm);
pdfDoc.addTrailerObject(destAcroForm);
catalog.put(COSName.ACRO_FORM.getName(), destAcroForm);
}
PDFArray clonedFields = (PDFArray) destAcroForm.get(COSName.FIELDS.getName());
if (clonedFields == null) {
clonedFields = new PDFArray();
destAcroForm.put(COSName.FIELDS.getName(), clonedFields);
}
for (Object field : fields) {
if (field instanceof COSBase) {
field = cloneForNewDocument(field, field, Arrays.asList(COSName.KIDS));
}
if (!clonedFields.contains(field)) {
clonedFields.add(field);
}
}
}