You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by ss...@apache.org on 2014/09/11 17:05:24 UTC
svn commit: r1624313 - in /xmlgraphics/fop-pdf-images/trunk: lib/
src/java/org/apache/fop/render/pdf/pdfbox/
test/java/org/apache/fop/render/pdf/
Author: ssteiner
Date: Thu Sep 11 15:05:23 2014
New Revision: 1624313
URL: http://svn.apache.org/r1624313
Log:
FOP-2411: PDF to PDF Link not working
Modified:
xmlgraphics/fop-pdf-images/trunk/lib/fop.jar
xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/AbstractPDFBoxHandler.java
xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java
xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxImageHandler.java
xmlgraphics/fop-pdf-images/trunk/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java
Modified: xmlgraphics/fop-pdf-images/trunk/lib/fop.jar
URL: http://svn.apache.org/viewvc/xmlgraphics/fop-pdf-images/trunk/lib/fop.jar?rev=1624313&r1=1624312&r2=1624313&view=diff
==============================================================================
Binary files - no diff available.
Modified: xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/AbstractPDFBoxHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/AbstractPDFBoxHandler.java?rev=1624313&r1=1624312&r2=1624313&view=diff
==============================================================================
--- xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/AbstractPDFBoxHandler.java (original)
+++ xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/AbstractPDFBoxHandler.java Thu Sep 11 15:05:23 2014
@@ -36,6 +36,7 @@ import org.apache.xmlgraphics.image.load
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.pdf.PDFArray;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFResources;
@@ -66,8 +67,8 @@ public abstract class AbstractPDFBoxHand
= Collections.synchronizedMap(new WeakHashMap<Object, Cache<String, Map<Object, Object>>>());
protected String createStreamForPDF(ImagePDF image, PDFPage targetPage, FOUserAgent userAgent,
- AffineTransform at, FontInfo fontinfo, Rectangle pos) throws IOException {
-
+ AffineTransform at, FontInfo fontinfo, Rectangle pos, Map<Integer, PDFArray> pageNumbers)
+ throws IOException {
EventBroadcaster eventBroadcaster = null;
if (userAgent != null) {
eventBroadcaster = userAgent.getEventBroadcaster();
@@ -115,9 +116,8 @@ public abstract class AbstractPDFBoxHand
targetPage.put("Resources", res);
}
- PDFBoxAdapter adapter = new PDFBoxAdapter(targetPage, objectCache);
- String stream = adapter.createStreamFromPDFBoxPage(pddoc, page, originalImageUri,
- eventBroadcaster, at, fontinfo, pos);
+ PDFBoxAdapter adapter = new PDFBoxAdapter(targetPage, objectCache, pageNumbers);
+ String stream = adapter.createStreamFromPDFBoxPage(pddoc, page, originalImageUri, at, fontinfo, pos);
return stream;
}
Modified: xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java?rev=1624313&r1=1624312&r2=1624313&view=diff
==============================================================================
--- xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java (original)
+++ xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java Thu Sep 11 15:05:23 2014
@@ -25,11 +25,13 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -39,6 +41,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
@@ -92,7 +95,6 @@ import org.apache.pdfbox.pdmodel.interac
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.util.operator.PDFOperator;
-import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.fonts.CIDFontType;
import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.EmbeddingMode;
@@ -127,7 +129,7 @@ public class PDFBoxAdapter {
/** logging instance */
protected static final Log log = LogFactory.getLog(PDFBoxAdapter.class);
- private static final Set FILTER_FILTER = new java.util.HashSet(
+ private static final Set FILTER_FILTER = new HashSet(
Arrays.asList(new String[] {"Filter", "DecodeParms"}));
private static final Pattern SUBSET_PATTERN = Pattern.compile("[A-Z][A-Z][A-Z][A-Z][A-Z][A-Z]\\+.+");
@@ -139,16 +141,19 @@ public class PDFBoxAdapter {
private final Map<COSDictionary, PDSimpleFont> fontMap = new HashMap<COSDictionary, PDSimpleFont>();
private Map<COSName, String> newXObj = new HashMap<COSName, String>();
private Collection<String> parentFonts;
+ private Map<Integer, PDFArray> pageNumbers;
/**
* Creates a new PDFBoxAdapter.
* @param targetPage The target FOP PDF page object
* @param objectCache the object cache for reusing objects shared by multiple pages.
+ * @param pageNumbers references to page object numbers
*/
- public PDFBoxAdapter(PDFPage targetPage, Map objectCache) {
+ public PDFBoxAdapter(PDFPage targetPage, Map objectCache, Map<Integer, PDFArray> pageNumbers) {
this.targetPage = targetPage;
this.pdfDoc = this.targetPage.getDocument();
this.clonedVersion = objectCache;
+ this.pageNumbers = pageNumbers;
}
private Object cloneForNewDocument(Object base) throws IOException {
@@ -1370,7 +1375,6 @@ public class PDFBoxAdapter {
* @param sourceDoc the source PDF the given page to be copied belongs to
* @param page the page to transform into a stream
* @param key value to use as key for the stream
- * @param eventBroadcaster events
* @param atdoc adjustment for stream
* @param fontinfo fonts
* @param pos rectangle
@@ -1378,11 +1382,14 @@ public class PDFBoxAdapter {
* @throws IOException if an I/O error occurs
*/
public String createStreamFromPDFBoxPage(PDDocument sourceDoc, PDPage page, String key,
- EventBroadcaster eventBroadcaster, AffineTransform atdoc, FontInfo fontinfo, Rectangle pos)
+ AffineTransform atdoc, FontInfo fontinfo, Rectangle pos)
throws IOException {
- handleAcroForm(sourceDoc, page, eventBroadcaster, atdoc);
+ handleAnnotations(sourceDoc, page, atdoc);
+ if (pageNumbers.containsKey(targetPage.getPageIndex())) {
+ pageNumbers.get(targetPage.getPageIndex()).set(0, targetPage.makeReference());
+ }
PDResources sourcePageResources = page.findResources();
- PDFDictionary pageResources = null;
+ PDFDictionary pageResources;
PDStream pdStream = page.getContents();
if (pdStream == null) {
return "";
@@ -1500,7 +1507,7 @@ public class PDFBoxAdapter {
//no additional transformations necessary
break;
}
- StringBuffer boxStr = new StringBuffer();
+ StringBuilder boxStr = new StringBuilder();
boxStr.append(0).append(' ').append(0).append(' ');
boxStr.append(PDFNumber.doubleOut(mediaBox.getWidth())).append(' ');
boxStr.append(PDFNumber.doubleOut(mediaBox.getHeight())).append(" re W n\n");
@@ -1643,8 +1650,7 @@ public class PDFBoxAdapter {
*/
}
- private void handleAcroForm(PDDocument sourceDoc, PDPage page,
- EventBroadcaster eventBroadcaster, AffineTransform at) throws IOException {
+ private void handleAnnotations(PDDocument sourceDoc, PDPage page, AffineTransform at) throws IOException {
PDDocumentCatalog srcCatalog = sourceDoc.getDocumentCatalog();
PDAcroForm srcAcroForm = srcCatalog.getAcroForm();
List pageAnnotations = page.getAnnotations();
@@ -1652,67 +1658,38 @@ public class PDFBoxAdapter {
return;
}
- PDRectangle mediaBox = page.findMediaBox();
- PDRectangle cropBox = page.findCropBox();
- PDRectangle viewBox = cropBox != null ? cropBox : mediaBox;
-
- for (Object obj : pageAnnotations) {
- PDAnnotation annot = (PDAnnotation)obj;
- PDRectangle rect = annot.getRectangle();
- rect.move((float)(at.getTranslateX() - viewBox.getLowerLeftX()),
- (float)at.getTranslateY() - viewBox.getLowerLeftY());
- }
+ moveAnnotations(page, pageAnnotations, at);
//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;
if (page.getCOSObject() instanceof COSObject) {
- cosPage = (COSObject)page.getCOSObject();
+ cosPage = (COSObject) page.getCOSObject();
+ cacheClonedObject(cosPage, this.targetPage);
} else {
PDPageNode pageNode = page.getParent();
-
- COSArray kids = (COSArray)pageNode.getDictionary().getDictionaryObject(COSName.KIDS);
- Iterator iter = kids.iterator();
- while (iter.hasNext()) {
+ COSArray kids = (COSArray) pageNode.getDictionary().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)iter.next();
+ 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;
- break;
}
}
if (cosPage == null) {
throw new IOException("Illegal PDF. Page not part of parent page node.");
}
}
- cacheClonedObject(cosPage, this.targetPage);
- COSArray annots = (COSArray) page.getCOSDictionary().getDictionaryObject(COSName.ANNOTS);
- Set<COSObject> fields = Collections.emptySet();
- if (annots != null) {
- fields = new HashSet();
- Iterator iter = annots.iterator();
- while (iter.hasNext()) {
- COSObject annot = (COSObject) iter.next();
- COSObject fieldObject = annot;
- COSDictionary field = (COSDictionary) fieldObject.getObject();
- if ("Widget".equals(field.getNameAsString(COSName.SUBTYPE))) {
- COSObject parent;
- while ((parent = (COSObject) field.getItem(COSName.PARENT)) != null) {
- fieldObject = parent;
- field = (COSDictionary) fieldObject.getObject();
- }
- fields.add(fieldObject);
- Collection<COSName> exclude = new ArrayList<COSName>();
- exclude.add(COSName.P);
- if (((COSDictionary)annot.getObject()).getItem(COSName.getPDFName("StructParent")) != null) {
- exclude.add(COSName.PARENT);
- }
- PDFObject clonedAnnot = (PDFObject) cloneForNewDocument(annot, annot, exclude);
- targetPage.addAnnotation(clonedAnnot);
- }
- }
- }
+ Set<COSObject> fields = copyAnnotations(page);
boolean formAlreadyCopied = getCachedClone(srcAcroForm) != null;
PDFRoot catalog = this.pdfDoc.getRoot();
@@ -1746,4 +1723,89 @@ public class PDFBoxAdapter {
clonedFields.add(clone);
}
}
+
+ private void updateAnnotationLink(PDFDictionary clonedAnnot) {
+ PDFDictionary a = (PDFDictionary) clonedAnnot.get("A");
+ if (a != null) {
+ PDFArray oldarray = (PDFArray) a.get("D");
+ if (oldarray != null) {
+ PDFArray newarray = (PDFArray) oldarray.get(0);
+ if (newarray != null) {
+ for (int i = 1; i < oldarray.length(); i++) {
+ newarray.add(oldarray.get(i));
+ }
+ a.put("D", oldarray.get(0));
+ }
+ }
+ }
+ }
+
+ private Set<COSObject> copyAnnotations(PDPage page) throws IOException {
+ COSArray annots = (COSArray) page.getCOSDictionary().getDictionaryObject(COSName.ANNOTS);
+ Set<COSObject> fields = Collections.emptySet();
+ if (annots != null) {
+ fields = new TreeSet<COSObject>(new CompareFields());
+ for (Object annot1 : annots) {
+ Collection<COSName> exclude = new ArrayList<COSName>();
+ exclude.add(COSName.P);
+ if (annot1 instanceof COSObject) {
+ COSObject annot = (COSObject) annot1;
+ COSObject fieldObject = annot;
+ COSDictionary field = (COSDictionary) fieldObject.getObject();
+ COSObject parent;
+ while ((parent = (COSObject) field.getItem(COSName.PARENT)) != null) {
+ fieldObject = parent;
+ field = (COSDictionary) fieldObject.getObject();
+ }
+ fields.add(fieldObject);
+
+ if (((COSDictionary) annot.getObject()).getItem(COSName.getPDFName("StructParent")) != null) {
+ exclude.add(COSName.PARENT);
+ }
+ }
+
+ PDFObject clonedAnnot = (PDFObject) cloneForNewDocument(annot1, annot1, exclude);
+ if (clonedAnnot instanceof PDFDictionary) {
+ clonedAnnot.setParent(targetPage);
+ updateAnnotationLink((PDFDictionary) clonedAnnot);
+ }
+ targetPage.addAnnotation(clonedAnnot);
+ }
+ }
+ return fields;
+ }
+
+ private void moveAnnotations(PDPage page, List pageAnnotations, AffineTransform at) {
+ PDRectangle mediaBox = page.findMediaBox();
+ PDRectangle cropBox = page.findCropBox();
+ PDRectangle viewBox = cropBox != null ? cropBox : mediaBox;
+ for (Object obj : pageAnnotations) {
+ PDAnnotation annot = (PDAnnotation)obj;
+ PDRectangle rect = annot.getRectangle();
+ float translateX = (float) (at.getTranslateX() - viewBox.getLowerLeftX());
+ float translateY = (float) (at.getTranslateY() - viewBox.getLowerLeftY());
+ if (rect != null) {
+ rect.move(translateX, translateY);
+ annot.setRectangle(rect);
+ }
+ COSArray vertices = (COSArray) annot.getDictionary().getDictionaryObject("Vertices");
+ if (vertices != null) {
+ Iterator iter = vertices.iterator();
+ while (iter.hasNext()) {
+ COSFloat x = (COSFloat) iter.next();
+ COSFloat y = (COSFloat) iter.next();
+ x.setValue(x.floatValue() + translateX);
+ y.setValue(y.floatValue() + translateY);
+ }
+ }
+ }
+ }
+
+ static class CompareFields implements Comparator<COSObject>, Serializable {
+ private static final long serialVersionUID = -6081505461660440801L;
+
+ public int compare(COSObject o1, COSObject o2) {
+ return o1.getObjectNumber().intValue() - o2.getObjectNumber().intValue();
+ }
+ }
}
Modified: xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxImageHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxImageHandler.java?rev=1624313&r1=1624312&r2=1624313&view=diff
==============================================================================
--- xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxImageHandler.java (original)
+++ xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxImageHandler.java Thu Sep 11 15:05:23 2014
@@ -70,7 +70,7 @@ public class PDFBoxImageHandler extends
}
FontInfo fontinfo = (FontInfo)context.getHint("fontinfo");
String stream = createStreamForPDF(pdfImage, pdfContext.getPage(), pdfContext.getUserAgent(),
- pageAdjust, fontinfo, pos);
+ pageAdjust, fontinfo, pos, pdfContext.getPageNumbers());
if (stream == null) {
return;
}
Modified: xmlgraphics/fop-pdf-images/trunk/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop-pdf-images/trunk/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java?rev=1624313&r1=1624312&r2=1624313&view=diff
==============================================================================
--- xmlgraphics/fop-pdf-images/trunk/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java (original)
+++ xmlgraphics/fop-pdf-images/trunk/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java Thu Sep 11 15:05:23 2014
@@ -25,13 +25,17 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.imageio.ImageIO;
+import org.apache.fop.pdf.PDFAnnotList;
+import org.apache.fop.pdf.PDFArray;
import org.apache.fop.pdf.PDFGState;
import org.apache.fop.render.pdf.pdfbox.ImagePDF;
import org.apache.fop.render.pdf.pdfbox.PDFBoxImageHandler;
@@ -85,12 +89,14 @@ public class PDFBoxAdapterTestCase {
private static final String Type1Subset4 = "test/resources/t1subset4.pdf";
private static final String ROTATE = "test/resources/rotate.pdf";
private static final String SHADING = "test/resources/shading.pdf";
+ private static final String LINK = "test/resources/link.pdf";
private PDFBoxAdapter getPDFBoxAdapter() {
PDFDocument doc = new PDFDocument("");
doc.setMergeFontsEnabled(true);
pdfpage.setDocument(doc);
- return new PDFBoxAdapter(pdfpage, new HashMap());
+ pdfpage.setObjectNumber(1);
+ return new PDFBoxAdapter(pdfpage, new HashMap(), new HashMap<Integer, PDFArray>());
}
@Test
@@ -152,7 +158,7 @@ public class PDFBoxAdapterTestCase {
PDDocument doc = PDDocument.load(pdf);
PDPage page = (PDPage) doc.getDocumentCatalog().getAllPages().get(0);
AffineTransform at = new AffineTransform();
- String c = getPDFBoxAdapter().createStreamFromPDFBoxPage(doc, page, pdf, null, at, fi, new Rectangle());
+ String c = getPDFBoxAdapter().createStreamFromPDFBoxPage(doc, page, pdf, at, fi, new Rectangle());
// PDResources sourcePageResources = page.findResources();
// COSDictionary fonts = (COSDictionary)sourcePageResources.getCOSDictionary().getDictionaryObject(COSName.FONT);
// PDFBoxAdapter.PDFWriter w = adapter. new MergeFontsPDFWriter(fonts, fi, "", new ArrayList<COSName>());
@@ -277,12 +283,12 @@ public class PDFBoxAdapterTestCase {
@Test
public void testStream() throws Exception {
pdfpage.setDocument(new PDFDocument(""));
- PDFBoxAdapter adapter = new PDFBoxAdapter(pdfpage, new HashMap());
+ PDFBoxAdapter adapter = new PDFBoxAdapter(pdfpage, new HashMap(), new HashMap<Integer, PDFArray>());
PDDocument doc = PDDocument.load(ROTATE);
PDPage page = (PDPage) doc.getDocumentCatalog().getAllPages().get(0);
AffineTransform at = new AffineTransform();
Rectangle r = new Rectangle(0, 1650, 842000, 595000);
- String stream = adapter.createStreamFromPDFBoxPage(doc, page, "key", null, at, null, r);
+ String stream = adapter.createStreamFromPDFBoxPage(doc, page, "key", at, null, r);
Assert.assertEquals(at, new AffineTransform(-0.0, 1.0000000554888686, 1.0000000554888686, 0.0, 0.0,
-2.0742416381835938E-5));
Assert.assertTrue(stream.contains("/GS0106079 gs"));
@@ -291,6 +297,26 @@ public class PDFBoxAdapterTestCase {
}
@Test
+ public void testLink() throws Exception {
+ pdfpage.setObjectNumber(1);
+ PDFDocument pdfdoc = new PDFDocument("");
+ pdfpage.setDocument(pdfdoc);
+ Map<Integer, PDFArray> pageNumbers = new HashMap<Integer, PDFArray>();
+ PDFBoxAdapter adapter = new PDFBoxAdapter(pdfpage, new HashMap(), pageNumbers);
+ PDDocument doc = PDDocument.load(LINK);
+ PDPage page = (PDPage) doc.getDocumentCatalog().getAllPages().get(0);
+ AffineTransform at = new AffineTransform();
+ Rectangle r = new Rectangle(0, 1650, 842000, 595000);
+ String stream = adapter.createStreamFromPDFBoxPage(doc, page, "key", at, null, r);
+ Assert.assertTrue(stream.contains("/Link <</MCID 5 >>BDC"));
+ Assert.assertTrue(pageNumbers.size() == 4);
+ PDFAnnotList annots = (PDFAnnotList) pdfpage.get("Annots");
+ Assert.assertEquals(annots.toPDFString(), "[\n9 0 R\n12 0 R\n]");
+// pdfdoc.output(System.out);
+ doc.close();
+ }
+
+ @Test
public void testPreloaderPDF() throws Exception {
ImageSource imageSource = new ImageSource(ImageIO.createImageInputStream(new File(ROTATE)), "", true);
ImageInfo imageInfo = new PreloaderPDF().preloadImage("", imageSource, new DefaultImageContext());
@@ -310,6 +336,7 @@ public class PDFBoxAdapterTestCase {
pdfpage.addGState(g);
PDFContentGenerator con = new PDFContentGenerator(pdfdoc, null, null);
PDFRenderingContext c = new PDFRenderingContext(null, con, pdfpage, null);
+ c.setPageNumbers(new HashMap<Integer, PDFArray>());
new PDFBoxImageHandler().handleImage(c, img, new Rectangle());
PDFResources res = c.getPage().getPDFResources();
OutputStream bos = new ByteArrayOutputStream();
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org