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 je...@apache.org on 2010/08/16 11:39:35 UTC
svn commit: r985843 - in /xmlgraphics/fop/trunk/src/java/org/apache/fop:
pdf/ render/pdf/
Author: jeremias
Date: Mon Aug 16 09:39:34 2010
New Revision: 985843
URL: http://svn.apache.org/viewvc?rev=985843&view=rev
Log:
Improvements/Bugfixes for PDF attachments (embedded files):
- Acrobat doesn't like indirect objects for the /Length entry of embedded files (make on-the-fly generation more easily configurable).
- Added the /Size entry for embedded files to keep Acrobat happy.
- Moved the embedded files' Names tree to the end of the PDF to be on the safe side.
- Made hyperlinks to embedded files work by using a JavaScript Action (thanks to Matthias Reischenbacher for that idea).
- Added sorting to the names tree node because Acrobat relies on it.
- Added some filename manipulation code to work around possible encoding problems with special characters in the filenames.
Added:
xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFJavaScriptLaunchAction.java (with props)
Modified:
xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/AbstractPDFStream.java
xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFArray.java
xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFEmbeddedFile.java
xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFactory.java
xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFileSpec.java
xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFGoToRemote.java
xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFNameTreeNode.java
xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFText.java
xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/AbstractPDFStream.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/AbstractPDFStream.java?rev=985843&r1=985842&r2=985843&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/AbstractPDFStream.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/AbstractPDFStream.java Mon Aug 16 09:39:34 2010
@@ -191,7 +191,7 @@ public abstract class AbstractPDFStream
StreamCache encodedStream = null;
PDFNumber refLength = null;
final Object lengthEntry;
- if (getDocument().isEncodingOnTheFly()) {
+ if (isEncodingOnTheFly()) {
refLength = new PDFNumber();
getDocumentSafely().registerObject(refLength);
lengthEntry = refLength;
@@ -218,6 +218,15 @@ public abstract class AbstractPDFStream
}
/**
+ * Indicates whether encoding may happen without buffering the encoded data. If this method
+ * returns true, the /Length entry will be an indirect object, a direct object otherwise.
+ * @return true if encoding should happen "on the fly"
+ */
+ protected boolean isEncodingOnTheFly() {
+ return getDocument().isEncodingOnTheFly();
+ }
+
+ /**
* Populates the dictionary with all necessary entries for the stream.
* Override this method if you need additional entries.
* @param lengthEntry value for the /Length entry
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFArray.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFArray.java?rev=985843&r1=985842&r2=985843&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFArray.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFArray.java Mon Aug 16 09:39:34 2010
@@ -172,6 +172,13 @@ public class PDFArray extends PDFObject
this.values.add(new Double(value));
}
+ /**
+ * Clears the PDF array.
+ */
+ public void clear() {
+ this.values.clear();
+ }
+
/** {@inheritDoc} */
protected int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFEmbeddedFile.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFEmbeddedFile.java?rev=985843&r1=985842&r2=985843&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFEmbeddedFile.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFEmbeddedFile.java Mon Aug 16 09:39:34 2010
@@ -19,6 +19,7 @@
package org.apache.fop.pdf;
+import java.io.IOException;
import java.util.Date;
/**
@@ -37,4 +38,22 @@ public class PDFEmbeddedFile extends PDF
put("Params", params);
}
+ /** {@inheritDoc} */
+ protected boolean isEncodingOnTheFly() {
+ //Acrobat doesn't like an indirect /Length object in this case,
+ //but only when the embedded file is a PDF file.
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ protected void populateStreamDict(Object lengthEntry) {
+ super.populateStreamDict(lengthEntry);
+ try {
+ PDFDictionary dict = (PDFDictionary)get("Params");
+ dict.put("Size", new Integer(data.getSize()));
+ } catch (IOException ioe) {
+ //ignore and just skip this entry as it's optional
+ }
+ }
+
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFactory.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFactory.java?rev=985843&r1=985842&r2=985843&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFactory.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFactory.java Mon Aug 16 09:39:34 2010
@@ -877,7 +877,8 @@ public class PDFFactory {
*/
public PDFNames makeNames() {
PDFNames names = new PDFNames();
- getDocument().registerObject(names);
+ getDocument().assignObjectNumber(names);
+ getDocument().addTrailerObject(names);
return names;
}
@@ -1067,7 +1068,7 @@ public class PDFFactory {
if (target.startsWith(EMBEDDED_FILE)) {
// File Attachments (Embedded Files)
String filename = target.substring(EMBEDDED_FILE.length());
- return getLaunchActionForEmbeddedFile(filename);
+ return getActionForEmbeddedFile(filename, newWindow);
} else if (targetLo.startsWith("http://")) {
// HTTP URL?
return new PDFUri(target);
@@ -1094,7 +1095,7 @@ public class PDFFactory {
}
}
- private PDFAction getLaunchActionForEmbeddedFile(String filename) {
+ private PDFAction getActionForEmbeddedFile(String filename, boolean newWindow) {
PDFNames names = getDocument().getRoot().getNames();
if (names == null) {
throw new IllegalStateException(
@@ -1107,6 +1108,9 @@ public class PDFFactory {
"No /EmbeddedFiles name tree present."
+ " Cannot create Launch Action for embedded file: " + filename);
}
+
+ //Find filespec reference for the embedded file
+ filename = PDFText.toPDFString(filename, '_');
PDFArray files = embeddedFiles.getNames();
PDFReference embeddedFileRef = null;
int i = 0;
@@ -1124,8 +1128,23 @@ public class PDFFactory {
throw new IllegalStateException(
"No embedded file with name " + filename + " present.");
}
- PDFLaunch launch = new PDFLaunch(embeddedFileRef);
- return launch;
+
+ //Finally create the action
+ //PDFLaunch action = new PDFLaunch(embeddedFileRef);
+ //This works with Acrobat 8 but not with Acrobat 9
+
+ //The following two options didn't seem to have any effect.
+ //PDFGoToEmbedded action = new PDFGoToEmbedded(embeddedFileRef, 0, newWindow);
+ //PDFGoToRemote action = new PDFGoToRemote(embeddedFileRef, 0, newWindow);
+
+ //This finally seems to work:
+ StringBuffer scriptBuffer = new StringBuffer();
+ scriptBuffer.append("this.exportDataObject({cName:\"");
+ scriptBuffer.append(filename);
+ scriptBuffer.append("\", nLaunch:2});)");
+
+ PDFJavaScriptLaunchAction action = new PDFJavaScriptLaunchAction(scriptBuffer.toString());
+ return action;
}
/**
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFileSpec.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFileSpec.java?rev=985843&r1=985842&r2=985843&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFileSpec.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFileSpec.java Mon Aug 16 09:39:34 2010
@@ -19,10 +19,8 @@
package org.apache.fop.pdf;
-
/**
- * class representing a /FileSpec object.
- *
+ * Class representing a /FileSpec object.
*/
public class PDFFileSpec extends PDFDictionary {
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFGoToRemote.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFGoToRemote.java?rev=985843&r1=985842&r2=985843&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFGoToRemote.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFGoToRemote.java Mon Aug 16 09:39:34 2010
@@ -27,7 +27,7 @@ public class PDFGoToRemote extends PDFAc
/**
* the file specification
*/
- private PDFFileSpec pdfFileSpec;
+ private PDFReference pdfFileSpec;
private int pageReference = 0;
private String destination = null;
private boolean newWindow = false;
@@ -43,12 +43,12 @@ public class PDFGoToRemote extends PDFAc
/* generic creation of object */
super();
- this.pdfFileSpec = pdfFileSpec;
+ this.pdfFileSpec = pdfFileSpec.makeReference();
this.newWindow = newWindow;
}
/**
- * create an GoToR object.
+ * Create an GoToR object.
*
* @param pdfFileSpec the fileSpec associated with the action
* @param page a page reference within the remote document
@@ -56,7 +56,18 @@ public class PDFGoToRemote extends PDFAc
* displayed in a new window
*/
public PDFGoToRemote(PDFFileSpec pdfFileSpec, int page, boolean newWindow) {
- /* generic creation of object */
+ this(pdfFileSpec.makeReference(), page, newWindow);
+ }
+
+ /**
+ * Create an GoToR object.
+ *
+ * @param pdfFileSpec the fileSpec associated with the action
+ * @param page a page reference within the remote document
+ * @param newWindow boolean indicating whether the target should be
+ * displayed in a new window
+ */
+ public PDFGoToRemote(PDFReference pdfFileSpec, int page, boolean newWindow) {
super();
this.pdfFileSpec = pdfFileSpec;
@@ -76,7 +87,7 @@ public class PDFGoToRemote extends PDFAc
/* generic creation of object */
super();
- this.pdfFileSpec = pdfFileSpec;
+ this.pdfFileSpec = pdfFileSpec.makeReference();
this.destination = dest;
this.newWindow = newWindow;
}
@@ -97,7 +108,7 @@ public class PDFGoToRemote extends PDFAc
StringBuffer sb = new StringBuffer(64);
sb.append(getObjectID());
sb.append("<<\n/S /GoToR\n/F ");
- sb.append(pdfFileSpec.referencePDF());
+ sb.append(pdfFileSpec.toString());
sb.append("\n");
if (destination != null) {
@@ -139,7 +150,7 @@ public class PDFGoToRemote extends PDFAc
PDFGoToRemote remote = (PDFGoToRemote)obj;
- if (!remote.pdfFileSpec.referencePDF().equals(pdfFileSpec.referencePDF())) {
+ if (!remote.pdfFileSpec.toString().equals(pdfFileSpec.toString())) {
return false;
}
Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFJavaScriptLaunchAction.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFJavaScriptLaunchAction.java?rev=985843&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFJavaScriptLaunchAction.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFJavaScriptLaunchAction.java Mon Aug 16 09:39:34 2010
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+/**
+ * PDF Action which executes some JavaScript code.
+ * @since PDF 1.3
+ */
+public class PDFJavaScriptLaunchAction extends PDFAction {
+
+ private String script;
+
+ /**
+ * Creates a new /Launch action.
+ * @param script the script to run when the launch action is triggered
+ */
+ public PDFJavaScriptLaunchAction(String script) {
+ this.script = script;
+ }
+
+ /** {@inheritDoc} */
+ public String getAction() {
+ return this.referencePDF();
+ }
+
+ /** {@inheritDoc} */
+ public String toPDFString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getObjectID());
+ sb.append("<<\n/S /JavaScript\n/JS (");
+ sb.append(this.script);
+ sb.append(")\n>>\nendobj\n");
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ protected boolean contentEquals(PDFObject obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null || !(obj instanceof PDFJavaScriptLaunchAction)) {
+ return false;
+ }
+
+ PDFJavaScriptLaunchAction launch = (PDFJavaScriptLaunchAction) obj;
+
+ if (!launch.script.toString().equals(script.toString())) {
+ return false;
+ }
+
+ return true;
+ }
+
+}
Propchange: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFJavaScriptLaunchAction.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFJavaScriptLaunchAction.java
------------------------------------------------------------------------------
svn:keywords = Id
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFNameTreeNode.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFNameTreeNode.java?rev=985843&r1=985842&r2=985843&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFNameTreeNode.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFNameTreeNode.java Mon Aug 16 09:39:34 2010
@@ -19,6 +19,14 @@
package org.apache.fop.pdf;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
/**
* Class representing a PDF name tree node.
*/
@@ -104,7 +112,6 @@ public class PDFNameTreeNode extends PDF
return (String)limits.get(1);
}
-
private PDFArray prepareLimitsArray() {
PDFArray limits = (PDFArray)get(LIMITS);
if (limits == null) {
@@ -117,5 +124,29 @@ public class PDFNameTreeNode extends PDF
return limits;
}
+ /** {@inheritDoc} */
+ protected void writeDictionary(OutputStream out, Writer writer) throws IOException {
+ sortNames(); //Sort the names before writing them out
+ super.writeDictionary(out, writer);
+ }
+
+ private void sortNames() {
+ PDFArray names = getNames();
+ SortedMap map = new TreeMap();
+ int i = 0;
+ int c = names.length();
+ while (i < c) {
+ String key = (String)names.get(i++); //Key must be a String
+ Object value = names.get(i++);
+ map.put(key, value);
+ }
+ names.clear();
+ Iterator iter = map.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry entry = (Map.Entry)iter.next();
+ names.add(entry.getKey());
+ names.add(entry.getValue());
+ }
+ }
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFText.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFText.java?rev=985843&r1=985842&r2=985843&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFText.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFText.java Mon Aug 16 09:39:34 2010
@@ -320,5 +320,41 @@ public class PDFText extends PDFObject {
return bout.toByteArray();
}
+ /**
+ * Converts a text to PDF's "string" data type. Unsupported characters get converted to '?'
+ * characters (similar to what the Java "US-ASCII" encoding does).
+ * @see {@link #toPDFString(CharSequence, char)}
+ * @param text the text to convert
+ * @return the converted string
+ */
+ public static String toPDFString(CharSequence text) {
+ return toPDFString(text, '?');
+ }
+
+ /**
+ * Converts a text to PDF's "string" data type. Unsupported characters get converted to the
+ * given replacement character.
+ * <p>
+ * The PDF library currently doesn't properly distinguish between the PDF
+ * data types "string" and "text string", so we currently restrict "string" to US-ASCII, also
+ * because "string" seems somewhat under-specified concerning the upper 128 bytes.
+ * @param text the text to convert
+ * @param replacement the replacement character used when substituting a character
+ * @return the converted string
+ */
+ public static String toPDFString(CharSequence text, char replacement) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0, c = text.length(); i < c; i++) {
+ char ch = text.charAt(i);
+ if (ch > 127) {
+ //TODO Revisit the restriction to US-ASCII once "string" and "text string" are
+ //"disentangled".
+ sb.append(replacement);
+ } else {
+ sb.append(ch);
+ }
+ }
+ return sb.toString();
+ }
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java?rev=985843&r1=985842&r2=985843&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java Mon Aug 16 09:39:34 2010
@@ -61,6 +61,7 @@ import org.apache.fop.pdf.PDFNumsArray;
import org.apache.fop.pdf.PDFOutputIntent;
import org.apache.fop.pdf.PDFPageLabels;
import org.apache.fop.pdf.PDFReference;
+import org.apache.fop.pdf.PDFText;
import org.apache.fop.pdf.PDFXMode;
import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileExtensionAttachment;
import org.apache.fop.util.ColorProfileUtil;
@@ -453,7 +454,8 @@ class PDFRenderingUtil implements PDFCon
}
PDFDictionary dict = new PDFDictionary();
dict.put("F", file);
- PDFFileSpec fileSpec = new PDFFileSpec(embeddedFile.getFilename());
+ String filename = PDFText.toPDFString(embeddedFile.getFilename(), '_');
+ PDFFileSpec fileSpec = new PDFFileSpec(filename);
fileSpec.setEmbeddedFile(dict);
if (embeddedFile.getDesc() != null) {
fileSpec.setDescription(embeddedFile.getDesc());
@@ -464,7 +466,8 @@ class PDFRenderingUtil implements PDFCon
PDFNameTreeNode embeddedFiles = names.getEmbeddedFiles();
if (embeddedFiles == null) {
embeddedFiles = new PDFNameTreeNode();
- //this.pdfDoc.registerObject(embeddedFiles);
+ this.pdfDoc.assignObjectNumber(embeddedFiles);
+ this.pdfDoc.addTrailerObject(embeddedFiles);
names.setEmbeddedFiles(embeddedFiles);
}
@@ -474,7 +477,8 @@ class PDFRenderingUtil implements PDFCon
nameArray = new PDFArray();
embeddedFiles.setNames(nameArray);
}
- nameArray.add(embeddedFile.getFilename());
+ String name = PDFText.toPDFString(filename);
+ nameArray.add(name);
nameArray.add(new PDFReference(fileSpec));
}
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org