aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/org')
-rw-r--r--src/java/org/apache/fop/pdf/AbstractPDFStream.java61
-rw-r--r--src/java/org/apache/fop/pdf/CompressedObject.java49
-rw-r--r--src/java/org/apache/fop/pdf/ObjectStream.java85
-rw-r--r--src/java/org/apache/fop/pdf/ObjectStreamManager.java69
-rw-r--r--src/java/org/apache/fop/pdf/PDFAnnotList.java5
-rw-r--r--src/java/org/apache/fop/pdf/PDFArray.java25
-rw-r--r--src/java/org/apache/fop/pdf/PDFCIDFont.java6
-rw-r--r--src/java/org/apache/fop/pdf/PDFCMap.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFDestination.java3
-rw-r--r--src/java/org/apache/fop/pdf/PDFDictionary.java11
-rw-r--r--src/java/org/apache/fop/pdf/PDFDocument.java390
-rw-r--r--src/java/org/apache/fop/pdf/PDFEncryption.java6
-rw-r--r--src/java/org/apache/fop/pdf/PDFEncryptionJCE.java24
-rw-r--r--src/java/org/apache/fop/pdf/PDFFactory.java29
-rw-r--r--src/java/org/apache/fop/pdf/PDFFilterList.java13
-rw-r--r--src/java/org/apache/fop/pdf/PDFFont.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFFormXObject.java4
-rw-r--r--src/java/org/apache/fop/pdf/PDFFunction.java24
-rw-r--r--src/java/org/apache/fop/pdf/PDFGState.java4
-rw-r--r--src/java/org/apache/fop/pdf/PDFGoTo.java4
-rw-r--r--src/java/org/apache/fop/pdf/PDFGoToRemote.java3
-rw-r--r--src/java/org/apache/fop/pdf/PDFICCBasedColorSpace.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFICCStream.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFImageXObject.java4
-rw-r--r--src/java/org/apache/fop/pdf/PDFInfo.java3
-rw-r--r--src/java/org/apache/fop/pdf/PDFLaunch.java3
-rw-r--r--src/java/org/apache/fop/pdf/PDFLink.java5
-rw-r--r--src/java/org/apache/fop/pdf/PDFMetadata.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFName.java13
-rw-r--r--src/java/org/apache/fop/pdf/PDFNumber.java6
-rw-r--r--src/java/org/apache/fop/pdf/PDFNumsArray.java11
-rw-r--r--src/java/org/apache/fop/pdf/PDFObject.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFOutline.java3
-rw-r--r--src/java/org/apache/fop/pdf/PDFOutputIntent.java3
-rw-r--r--src/java/org/apache/fop/pdf/PDFPages.java9
-rw-r--r--src/java/org/apache/fop/pdf/PDFPattern.java7
-rw-r--r--src/java/org/apache/fop/pdf/PDFResources.java4
-rw-r--r--src/java/org/apache/fop/pdf/PDFRoot.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFShading.java5
-rw-r--r--src/java/org/apache/fop/pdf/PDFStream.java30
-rw-r--r--src/java/org/apache/fop/pdf/PDFStructElem.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFT1Stream.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFTTFStream.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFText.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFUri.java3
-rw-r--r--src/java/org/apache/fop/pdf/PDFXObject.java4
-rw-r--r--src/java/org/apache/fop/pdf/Version.java7
-rw-r--r--src/java/org/apache/fop/pdf/xref/CompressedObjectReference.java66
-rw-r--r--src/java/org/apache/fop/pdf/xref/CrossReferenceObject.java46
-rw-r--r--src/java/org/apache/fop/pdf/xref/CrossReferenceStream.java107
-rw-r--r--src/java/org/apache/fop/pdf/xref/CrossReferenceTable.java73
-rw-r--r--src/java/org/apache/fop/pdf/xref/ObjectReference.java39
-rw-r--r--src/java/org/apache/fop/pdf/xref/TrailerDictionary.java94
-rw-r--r--src/java/org/apache/fop/pdf/xref/UncompressedObjectReference.java48
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java6
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java7
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java6
57 files changed, 1051 insertions, 398 deletions
diff --git a/src/java/org/apache/fop/pdf/AbstractPDFStream.java b/src/java/org/apache/fop/pdf/AbstractPDFStream.java
index 1b25c113f..0181728b8 100644
--- a/src/java/org/apache/fop/pdf/AbstractPDFStream.java
+++ b/src/java/org/apache/fop/pdf/AbstractPDFStream.java
@@ -29,16 +29,48 @@ import org.apache.fop.util.CloseBlockerOutputStream;
/**
* This is an abstract base class for PDF streams.
*/
-public abstract class AbstractPDFStream extends PDFDictionary {
+public abstract class AbstractPDFStream extends PDFObject {
+
+ private final PDFDictionary dictionary;
/** The filters that should be applied */
private PDFFilterList filters;
+ private final boolean encodeOnTheFly;
+
+ protected AbstractPDFStream() {
+ this(true);
+ }
+
+ protected AbstractPDFStream(PDFDictionary dictionary) {
+ this(dictionary, true);
+ }
+
+ protected AbstractPDFStream(boolean encodeOnTheFly) {
+ this(new PDFDictionary(), encodeOnTheFly);
+ }
+
+ protected AbstractPDFStream(PDFDictionary dictionary, boolean encodeOnTheFly) {
+ this.dictionary = dictionary;
+ this.encodeOnTheFly = encodeOnTheFly;
+ }
+
+ protected final PDFDictionary getDictionary() {
+ return dictionary;
+ }
+
+ protected Object get(String key) {
+ return dictionary.get(key);
+ }
+
/**
- * Constructor for AbstractPDFStream.
+ * Puts the given object in the dictionary associated to this stream.
+ *
+ * @param key the key in the dictionary
+ * @param value the value to store
*/
- public AbstractPDFStream() {
- super();
+ public void put(String key, Object value) {
+ dictionary.put(key, value);
}
/**
@@ -180,17 +212,16 @@ public abstract class AbstractPDFStream extends PDFDictionary {
* {@inheritDoc}
*/
@Override
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
setupFilterList();
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
- textBuffer.append(getObjectID());
StreamCache encodedStream = null;
PDFNumber refLength = null;
final Object lengthEntry;
- if (isEncodingOnTheFly()) {
+ if (encodeOnTheFly) {
refLength = new PDFNumber();
getDocumentSafely().registerObject(refLength);
lengthEntry = refLength;
@@ -200,7 +231,7 @@ public abstract class AbstractPDFStream extends PDFDictionary {
}
populateStreamDict(lengthEntry);
- writeDictionary(cout, textBuffer);
+ dictionary.writeDictionary(cout, textBuffer);
//Send encoded stream to target OutputStream
PDFDocument.flushTextBuffer(textBuffer, cout);
@@ -211,18 +242,14 @@ public abstract class AbstractPDFStream extends PDFDictionary {
encodedStream.clear(); //Encoded stream can now be discarded
}
- textBuffer.append("\nendobj\n");
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
- /**
- * 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();
+ @Override
+ public void setDocument(PDFDocument doc) {
+ dictionary.setDocument(doc);
+ super.setDocument(doc);
}
/**
@@ -233,7 +260,7 @@ public abstract class AbstractPDFStream extends PDFDictionary {
protected void populateStreamDict(Object lengthEntry) {
put("Length", lengthEntry);
if (!getFilterList().isDisableAllFilters()) {
- getFilterList().putFilterDictEntries(this);
+ getFilterList().putFilterDictEntries(dictionary);
}
}
diff --git a/src/java/org/apache/fop/pdf/CompressedObject.java b/src/java/org/apache/fop/pdf/CompressedObject.java
new file mode 100644
index 000000000..55d9c2953
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/CompressedObject.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Represents a PDF object that may appear in an object stream. An object stream is a PDF
+ * stream whose content is a sequence of PDF objects. See Section 3.4.6 of the PDF 1.5
+ * Reference.
+ */
+interface CompressedObject {
+
+ /**
+ * Returns the object number of this indirect object. Note that a compressed object
+ * must have a generation number of 0.
+ *
+ * @return the object number.
+ */
+ int getObjectNumber();
+
+ /**
+ * Outputs this object's content into the given stream.
+ *
+ * @param outputStream a stream, likely to be provided by the containing object stream
+ * @return the number of bytes written to the stream
+ * @throws IOException
+ */
+ int output(OutputStream outputStream) throws IOException;
+
+}
diff --git a/src/java/org/apache/fop/pdf/ObjectStream.java b/src/java/org/apache/fop/pdf/ObjectStream.java
new file mode 100644
index 000000000..e9335bc6f
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/ObjectStream.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.fop.pdf.xref.CompressedObjectReference;
+
+/**
+ * An object stream, as described in section 3.4.6 of the PDF 1.5 Reference.
+ */
+public class ObjectStream extends PDFStream {
+
+ private static final PDFName OBJ_STM = new PDFName("ObjStm");
+
+ private List<CompressedObject> objects = new ArrayList<CompressedObject>();
+
+ private int firstObjectOffset;
+
+ ObjectStream() {
+ super(false);
+ }
+
+ ObjectStream(ObjectStream previous) {
+ this();
+ put("Extends", previous);
+ }
+
+ CompressedObjectReference addObject(CompressedObject obj) {
+ if (obj == null) {
+ throw new NullPointerException("obj must not be null");
+ }
+ CompressedObjectReference reference = new CompressedObjectReference(obj.getObjectNumber(),
+ getObjectNumber(), objects.size());
+ objects.add(obj);
+ return reference;
+ }
+
+ @Override
+ protected void outputRawStreamData(OutputStream out) throws IOException {
+ int currentOffset = 0;
+ StringBuilder offsetsPart = new StringBuilder();
+ ByteArrayOutputStream streamContent = new ByteArrayOutputStream();
+ for (CompressedObject object : objects) {
+ offsetsPart.append(object.getObjectNumber())
+ .append(' ')
+ .append(currentOffset)
+ .append('\n');
+ currentOffset += object.output(streamContent);
+ }
+ byte[] offsets = PDFDocument.encode(offsetsPart.toString());
+ firstObjectOffset = offsets.length;
+ out.write(offsets);
+ streamContent.writeTo(out);
+ }
+
+ @Override
+ protected void populateStreamDict(Object lengthEntry) {
+ put("Type", OBJ_STM);
+ put("N", objects.size());
+ put("First", firstObjectOffset);
+ super.populateStreamDict(lengthEntry);
+ }
+}
diff --git a/src/java/org/apache/fop/pdf/ObjectStreamManager.java b/src/java/org/apache/fop/pdf/ObjectStreamManager.java
new file mode 100644
index 000000000..723facd96
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/ObjectStreamManager.java
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.fop.pdf.xref.CompressedObjectReference;
+
+/**
+ * Manages a collection of object streams, creating new streams as necessary to keep the
+ * number of objects in each stream at the recommended value. Streams are related to each
+ * other through the use of the Extends entry in the stream dictionary.
+ */
+class ObjectStreamManager {
+
+ private static final int OBJECT_STREAM_CAPACITY = 100;
+
+ private final PDFDocument pdfDocument;
+
+ private final List<CompressedObjectReference> compressedObjectReferences;
+
+ private int numObjectsInStream;
+
+ private ObjectStream currentObjectStream;
+
+ ObjectStreamManager(PDFDocument pdfDocument) {
+ this.pdfDocument = pdfDocument;
+ createObjectStream();
+ compressedObjectReferences = new ArrayList<CompressedObjectReference>();
+ }
+
+ void add(CompressedObject compressedObject) {
+ if (numObjectsInStream++ == OBJECT_STREAM_CAPACITY) {
+ createObjectStream();
+ numObjectsInStream = 1;
+ }
+ compressedObjectReferences.add(currentObjectStream.addObject(compressedObject));
+ }
+
+ private void createObjectStream() {
+ currentObjectStream = currentObjectStream == null
+ ? new ObjectStream()
+ : new ObjectStream(currentObjectStream);
+ pdfDocument.assignObjectNumber(currentObjectStream);
+ pdfDocument.addTrailerObject(currentObjectStream);
+ }
+
+ List<CompressedObjectReference> getCompressedObjectReferences() {
+ return compressedObjectReferences;
+ }
+}
diff --git a/src/java/org/apache/fop/pdf/PDFAnnotList.java b/src/java/org/apache/fop/pdf/PDFAnnotList.java
index 0a8710627..65b327e31 100644
--- a/src/java/org/apache/fop/pdf/PDFAnnotList.java
+++ b/src/java/org/apache/fop/pdf/PDFAnnotList.java
@@ -58,22 +58,19 @@ public class PDFAnnotList extends PDFObject {
*/
public String toPDFString() {
StringBuffer p = new StringBuffer(128);
- p.append(getObjectID());
p.append("[\n");
for (int i = 0; i < getCount(); i++) {
p.append(((PDFObject)links.get(i)).referencePDF());
p.append("\n");
}
- p.append("]\nendobj\n");
+ p.append("]");
return p.toString();
}
/*
* example
- * 20 0 obj
* [
* 19 0 R
* ]
- * endobj
*/
}
diff --git a/src/java/org/apache/fop/pdf/PDFArray.java b/src/java/org/apache/fop/pdf/PDFArray.java
index 78eba3bb9..131830328 100644
--- a/src/java/org/apache/fop/pdf/PDFArray.java
+++ b/src/java/org/apache/fop/pdf/PDFArray.java
@@ -21,7 +21,6 @@ package org.apache.fop.pdf;
import java.io.IOException;
import java.io.OutputStream;
-import java.util.Collection;
import java.util.List;
import org.apache.commons.io.output.CountingOutputStream;
@@ -48,7 +47,7 @@ public class PDFArray extends PDFObject {
* Create a new, empty array object with no parent.
*/
public PDFArray() {
- this(null);
+ this((PDFObject) null);
}
/**
@@ -84,7 +83,7 @@ public class PDFArray extends PDFObject {
* @param parent the array's parent if any
* @param values the actual values wrapped by this object
*/
- public PDFArray(PDFObject parent, Collection<Object> values) {
+ public PDFArray(PDFObject parent, List<?> values) {
/* generic creation of PDF object */
super(parent);
@@ -92,6 +91,15 @@ public class PDFArray extends PDFObject {
}
/**
+ * Creates an array object made of the given elements.
+ *
+ * @param elements the array content
+ */
+ public PDFArray(Object... elements) {
+ this(null, elements);
+ }
+
+ /**
* Create the array object
* @param parent the array's parent if any
* @param values the actual array wrapped by this object
@@ -180,13 +188,9 @@ public class PDFArray extends PDFObject {
/** {@inheritDoc} */
@Override
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
- if (hasObjectNumber()) {
- textBuffer.append(getObjectID());
- }
-
textBuffer.append('[');
for (int i = 0; i < values.size(); i++) {
if (i > 0) {
@@ -196,11 +200,6 @@ public class PDFArray extends PDFObject {
formatObject(obj, cout, textBuffer);
}
textBuffer.append(']');
-
- if (hasObjectNumber()) {
- textBuffer.append("\nendobj\n");
- }
-
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
diff --git a/src/java/org/apache/fop/pdf/PDFCIDFont.java b/src/java/org/apache/fop/pdf/PDFCIDFont.java
index 459fe2584..46374d869 100644
--- a/src/java/org/apache/fop/pdf/PDFCIDFont.java
+++ b/src/java/org/apache/fop/pdf/PDFCIDFont.java
@@ -200,7 +200,6 @@ public class PDFCIDFont extends PDFObject {
*/
public String toPDFString() {
StringBuffer p = new StringBuffer(128);
- p.append(getObjectID());
p.append("<< /Type /Font");
p.append("\n/BaseFont /");
p.append(this.basefont);
@@ -234,14 +233,13 @@ public class PDFCIDFont extends PDFObject {
p.append("\n/DW2 ["); // always two values, see p 211
p.append(this.dw2[0]);
p.append(this.dw2[1]);
- p.append("] \n>>\nendobj\n");
+ p.append("]");
}
if (w2 != null) {
p.append("\n/W2 ");
p.append(w2.toPDFString());
- p.append(" \n>>\nendobj\n");
}
- p.append(" \n>>\nendobj\n");
+ p.append("\n>>");
return p.toString();
}
diff --git a/src/java/org/apache/fop/pdf/PDFCMap.java b/src/java/org/apache/fop/pdf/PDFCMap.java
index 57d148fc2..34bc0f952 100644
--- a/src/java/org/apache/fop/pdf/PDFCMap.java
+++ b/src/java/org/apache/fop/pdf/PDFCMap.java
@@ -423,7 +423,7 @@ public class PDFCMap extends PDFStream {
}
/** {@inheritDoc} */
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
CMapBuilder builder = createCMapBuilder(getBufferWriter());
builder.writeCMap();
return super.output(stream);
diff --git a/src/java/org/apache/fop/pdf/PDFDestination.java b/src/java/org/apache/fop/pdf/PDFDestination.java
index 400c4a4b6..21c655832 100644
--- a/src/java/org/apache/fop/pdf/PDFDestination.java
+++ b/src/java/org/apache/fop/pdf/PDFDestination.java
@@ -50,9 +50,8 @@ public class PDFDestination extends PDFObject {
this.idRef = idRef;
}
- /** {@inheritDoc} */
@Override
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
diff --git a/src/java/org/apache/fop/pdf/PDFDictionary.java b/src/java/org/apache/fop/pdf/PDFDictionary.java
index 5a6724304..6bacd31a3 100644
--- a/src/java/org/apache/fop/pdf/PDFDictionary.java
+++ b/src/java/org/apache/fop/pdf/PDFDictionary.java
@@ -98,19 +98,10 @@ public class PDFDictionary extends PDFObject {
/** {@inheritDoc} */
@Override
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
- if (hasObjectNumber()) {
- textBuffer.append(getObjectID());
- }
-
writeDictionary(cout, textBuffer);
-
- if (hasObjectNumber()) {
- textBuffer.append("\nendobj\n");
- }
-
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java
index e9886fc37..9850c605e 100644
--- a/src/java/org/apache/fop/pdf/PDFDocument.java
+++ b/src/java/org/apache/fop/pdf/PDFDocument.java
@@ -26,6 +26,7 @@ import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@@ -37,6 +38,10 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fop.pdf.xref.CrossReferenceStream;
+import org.apache.fop.pdf.xref.CrossReferenceTable;
+import org.apache.fop.pdf.xref.TrailerDictionary;
+
/* image support modified from work of BoBoGi */
/* font support based on work by Takayuki Takeuchi */
@@ -63,31 +68,28 @@ import org.apache.commons.logging.LogFactory;
*/
public class PDFDocument {
- private static final Long LOCATION_PLACEHOLDER = new Long(0);
-
/** the encoding to use when converting strings to PDF commands */
public static final String ENCODING = "ISO-8859-1";
/** the counter for object numbering */
- protected int objectcount = 0;
+ protected int objectcount;
/** the logger instance */
private Log log = LogFactory.getLog("org.apache.fop.pdf");
/** the current character position */
- private long position = 0;
-
- /** character position of xref table */
- private long xref;
+ private long position;
/** the character position of each object */
- private List<Long> location = new ArrayList<Long>();
+ private List<Long> indirectObjectOffsets = new ArrayList<Long>();
+
+ private Collection<PDFStructElem> structureTreeElements;
/** List of objects to write in the trailer */
- private List trailerObjects = new ArrayList();
+ private List<PDFObject> trailerObjects = new ArrayList<PDFObject>();
/** the objects themselves */
- private List objects = new LinkedList();
+ private List<PDFObject> objects = new LinkedList<PDFObject>();
/** Controls the PDF version of this document */
private VersionController versionController;
@@ -99,7 +101,7 @@ public class PDFDocument {
private PDFRoot root;
/** The root outline object */
- private PDFOutline outlineRoot = null;
+ private PDFOutline outlineRoot;
/** The /Pages object (mark-fop@inomial.com) */
private PDFPages pages;
@@ -118,66 +120,47 @@ public class PDFDocument {
= new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB);
/** the counter for Pattern name numbering (e.g. 'Pattern1') */
- private int patternCount = 0;
+ private int patternCount;
/** the counter for Shading name numbering */
- private int shadingCount = 0;
+ private int shadingCount;
/** the counter for XObject numbering */
- private int xObjectCount = 0;
+ private int xObjectCount;
- /** the {@link PDFXObject}s map */
/* TODO: Should be modified (works only for image subtype) */
- private Map xObjectsMap = new HashMap();
-
- /** The {@link PDFFont} map */
- private Map fontMap = new HashMap();
+ private Map<String, PDFXObject> xObjectsMap = new HashMap<String, PDFXObject>();
- /** The {@link PDFFilter} map */
- private Map filterMap = new HashMap();
+ private Map<String, PDFFont> fontMap = new HashMap<String, PDFFont>();
- /** List of {@link PDFGState}s. */
- private List gstates = new ArrayList();
+ private Map<String, List<String>> filterMap = new HashMap<String, List<String>>();
- /** List of {@link PDFFunction}s. */
- private List functions = new ArrayList();
+ private List<PDFGState> gstates = new ArrayList<PDFGState>();
- /** List of {@link PDFShading}s. */
- private List shadings = new ArrayList();
+ private List<PDFFunction> functions = new ArrayList<PDFFunction>();
- /** List of {@link PDFPattern}s. */
- private List patterns = new ArrayList();
+ private List<PDFShading> shadings = new ArrayList<PDFShading>();
- /** List of {@link PDFLink}s. */
- private List links = new ArrayList();
+ private List<PDFPattern> patterns = new ArrayList<PDFPattern>();
- /** List of {@link PDFDestination}s. */
- private List destinations;
+ private List<PDFLink> links = new ArrayList<PDFLink>();
- /** List of {@link PDFFileSpec}s. */
- private List filespecs = new ArrayList();
+ private List<PDFDestination> destinations;
- /** List of {@link PDFGoToRemote}s. */
- private List gotoremotes = new ArrayList();
+ private List<PDFFileSpec> filespecs = new ArrayList<PDFFileSpec>();
- /** List of {@link PDFGoTo}s. */
- private List gotos = new ArrayList();
+ private List<PDFGoToRemote> gotoremotes = new ArrayList<PDFGoToRemote>();
- /** List of {@link PDFLaunch}es. */
- private List launches = new ArrayList();
+ private List<PDFGoTo> gotos = new ArrayList<PDFGoTo>();
- /**
- * The PDFDests object for the name dictionary.
- * Note: This object is not a list.
- */
- private PDFDests dests;
+ private List<PDFLaunch> launches = new ArrayList<PDFLaunch>();
private PDFFactory factory;
- private boolean encodingOnTheFly = true;
-
private FileIDGenerator fileIDGenerator;
+ private boolean accessibilityEnabled;
+
/**
* Creates an empty PDF document.
*
@@ -266,17 +249,6 @@ public class PDFDocument {
}
/**
- * Indicates whether stream encoding on-the-fly is enabled. If enabled
- * stream can be serialized without the need for a buffer to merely
- * calculate the stream length.
- *
- * @return <code>true</code> if on-the-fly encoding is enabled
- */
- public boolean isEncodingOnTheFly() {
- return this.encodingOnTheFly;
- }
-
- /**
* Converts text to a byte array for writing to a PDF file.
*
* @param text text to convert/encode
@@ -336,7 +308,7 @@ public class PDFDocument {
*
* @param map the map of filter lists for each stream type
*/
- public void setFilterMap(Map map) {
+ public void setFilterMap(Map<String, List<String>> map) {
this.filterMap = map;
}
@@ -345,7 +317,7 @@ public class PDFDocument {
*
* @return the map of filters being used
*/
- public Map getFilterMap() {
+ public Map<String, List<String>> getFilterMap() {
return this.filterMap;
}
@@ -368,6 +340,37 @@ public class PDFDocument {
}
/**
+ * Creates and returns a StructTreeRoot object.
+ *
+ * @param parentTree the value of the ParenTree entry
+ * @return the structure tree root
+ */
+ public PDFStructTreeRoot makeStructTreeRoot(PDFParentTree parentTree) {
+ PDFStructTreeRoot structTreeRoot = new PDFStructTreeRoot(parentTree);
+ assignObjectNumber(structTreeRoot);
+ addTrailerObject(structTreeRoot);
+ root.setStructTreeRoot(structTreeRoot);
+ structureTreeElements = new ArrayList<PDFStructElem>();
+ return structTreeRoot;
+ }
+
+ /**
+ * Creates and returns a structure element.
+ *
+ * @param structureType the structure type of the new element (value for the
+ * S entry)
+ * @param parent the parent of the new structure element in the structure
+ * hierarchy
+ * @return a dictionary of type StructElem
+ */
+ public PDFStructElem makeStructureElement(PDFName structureType, PDFObject parent) {
+ PDFStructElem structElem = new PDFStructElem(parent, structureType);
+ assignObjectNumber(structElem);
+ structureTreeElements.add(structElem);
+ return structElem;
+ }
+
+ /**
* Get the {@link PDFInfo} object for this document.
*
* @return the {@link PDFInfo} object
@@ -439,39 +442,39 @@ public class PDFDocument {
//Add object to special lists where necessary
if (obj instanceof PDFFunction) {
- this.functions.add(obj);
+ this.functions.add((PDFFunction) obj);
}
if (obj instanceof PDFShading) {
final String shadingName = "Sh" + (++this.shadingCount);
((PDFShading)obj).setName(shadingName);
- this.shadings.add(obj);
+ this.shadings.add((PDFShading) obj);
}
if (obj instanceof PDFPattern) {
final String patternName = "Pa" + (++this.patternCount);
((PDFPattern)obj).setName(patternName);
- this.patterns.add(obj);
+ this.patterns.add((PDFPattern) obj);
}
if (obj instanceof PDFFont) {
final PDFFont font = (PDFFont)obj;
this.fontMap.put(font.getName(), font);
}
if (obj instanceof PDFGState) {
- this.gstates.add(obj);
+ this.gstates.add((PDFGState) obj);
}
if (obj instanceof PDFPage) {
this.pages.notifyKidRegistered((PDFPage)obj);
}
if (obj instanceof PDFLaunch) {
- this.launches.add(obj);
+ this.launches.add((PDFLaunch) obj);
}
if (obj instanceof PDFLink) {
- this.links.add(obj);
+ this.links.add((PDFLink) obj);
}
if (obj instanceof PDFFileSpec) {
- this.filespecs.add(obj);
+ this.filespecs.add((PDFFileSpec) obj);
}
if (obj instanceof PDFGoToRemote) {
- this.gotoremotes.add(obj);
+ this.gotoremotes.add((PDFGoToRemote) obj);
}
}
@@ -485,7 +488,7 @@ public class PDFDocument {
this.trailerObjects.add(obj);
if (obj instanceof PDFGoTo) {
- this.gotos.add(obj);
+ this.gotos.add((PDFGoTo) obj);
}
}
@@ -537,9 +540,8 @@ public class PDFDocument {
return this.encryption;
}
- private Object findPDFObject(List list, PDFObject compare) {
- for (Iterator iter = list.iterator(); iter.hasNext();) {
- PDFObject obj = (PDFObject) iter.next();
+ private Object findPDFObject(List<? extends PDFObject> list, PDFObject compare) {
+ for (PDFObject obj : list) {
if (compare.contentEquals(obj)) {
return obj;
}
@@ -589,7 +591,7 @@ public class PDFDocument {
* @return PDFFont the requested font, null if it wasn't found
*/
protected PDFFont findFont(String fontname) {
- return (PDFFont)this.fontMap.get(fontname);
+ return this.fontMap.get(fontname);
}
/**
@@ -601,7 +603,7 @@ public class PDFDocument {
protected PDFDestination findDestination(PDFDestination compare) {
int index = getDestinationList().indexOf(compare);
if (index >= 0) {
- return (PDFDestination)getDestinationList().get(index);
+ return getDestinationList().get(index);
} else {
return null;
}
@@ -666,9 +668,9 @@ public class PDFDocument {
*/
protected PDFGState findGState(PDFGState wanted, PDFGState current) {
PDFGState poss;
- Iterator iter = this.gstates.iterator();
+ Iterator<PDFGState> iter = this.gstates.iterator();
while (iter.hasNext()) {
- PDFGState avail = (PDFGState)iter.next();
+ PDFGState avail = iter.next();
poss = new PDFGState();
poss.addValues(current);
poss.addValues(avail);
@@ -712,7 +714,7 @@ public class PDFDocument {
*
* @return the map of fonts used in this document
*/
- public Map getFontMap() {
+ public Map<String, PDFFont> getFontMap() {
return this.fontMap;
}
@@ -753,16 +755,7 @@ public class PDFDocument {
* @return the PDFXObject for the key if found
*/
public PDFXObject getXObject(String key) {
- return (PDFXObject)this.xObjectsMap.get(key);
- }
-
- /**
- * Gets the PDFDests object (which represents the /Dests entry).
- *
- * @return the PDFDests object (which represents the /Dests entry).
- */
- public PDFDests getDests() {
- return this.dests;
+ return this.xObjectsMap.get(key);
}
/**
@@ -771,7 +764,7 @@ public class PDFDocument {
*/
public void addDestination(PDFDestination destination) {
if (this.destinations == null) {
- this.destinations = new ArrayList();
+ this.destinations = new ArrayList<PDFDestination>();
}
this.destinations.add(destination);
}
@@ -781,11 +774,11 @@ public class PDFDocument {
*
* @return the list of named destinations.
*/
- public List getDestinationList() {
+ public List<PDFDestination> getDestinationList() {
if (hasDestinations()) {
return this.destinations;
} else {
- return Collections.EMPTY_LIST;
+ return Collections.emptyList();
}
}
@@ -900,17 +893,8 @@ public class PDFDocument {
return this.resources;
}
- /**
- * Ensure there is room in the locations xref for the number of
- * objects that have been created.
- * @param objidx the object's index
- * @param position the position
- */
- private void setLocation(int objidx, long position) {
- while (this.location.size() <= objidx) {
- this.location.add(LOCATION_PLACEHOLDER);
- }
- this.location.set(objidx, position);
+ public void enableAccessibility(boolean enableAccessibility) {
+ this.accessibilityEnabled = enableAccessibility;
}
/**
@@ -924,23 +908,50 @@ public class PDFDocument {
//LinkedList) allows for output() methods to create and register objects
//on the fly even during serialization.
while (this.objects.size() > 0) {
- /* Retrieve first */
- PDFObject object = (PDFObject)this.objects.remove(0);
- /*
- * add the position of this object to the list of object
- * locations
- */
- setLocation(object.getObjectNumber() - 1, this.position);
-
- /*
- * output the object and increment the character position
- * by the object's length
- */
- this.position += object.output(stream);
+ PDFObject object = this.objects.remove(0);
+ streamIndirectObject(object, stream);
}
+ }
- //Clear all objects written to the file
- //this.objects.clear();
+ private void streamIndirectObject(PDFObject o, OutputStream stream) throws IOException {
+ recordObjectOffset(o);
+ this.position += outputIndirectObject(o, stream);
+ }
+
+ private void streamIndirectObjects(Collection<? extends PDFObject> objects, OutputStream stream)
+ throws IOException {
+ for (PDFObject o : objects) {
+ streamIndirectObject(o, stream);
+ }
+ }
+
+ private void recordObjectOffset(PDFObject object) {
+ int index = object.getObjectNumber() - 1;
+ while (indirectObjectOffsets.size() <= index) {
+ indirectObjectOffsets.add(null);
+ }
+ indirectObjectOffsets.set(index, position);
+ }
+
+ /**
+ * Outputs the given object, wrapped by obj/endobj, to the given stream.
+ *
+ * @param object an indirect object, as described in Section 3.2.9 of the PDF 1.5
+ * Reference.
+ * @param stream the stream to which the object must be output
+ * @throws IllegalArgumentException if the object is not an indirect object
+ */
+ public static int outputIndirectObject(PDFObject object, OutputStream stream)
+ throws IOException {
+ if (!object.hasObjectNumber()) {
+ throw new IllegalArgumentException("Not an indirect object");
+ }
+ byte[] obj = encode(object.getObjectID());
+ stream.write(obj);
+ int length = object.output(stream);
+ byte[] endobj = encode("\nendobj\n");
+ stream.write(endobj);
+ return obj.length + length + endobj.length;
}
/**
@@ -980,89 +991,102 @@ public class PDFDocument {
* @throws IOException if there is an exception writing to the output stream
*/
public void outputTrailer(OutputStream stream) throws IOException {
+ createDestinations();
+ output(stream);
+ outputTrailerObjectsAndXref(stream);
+ }
+
+ private void createDestinations() {
if (hasDestinations()) {
Collections.sort(this.destinations, new DestinationComparator());
- this.dests = getFactory().makeDests(this.destinations);
+ PDFDests dests = getFactory().makeDests(this.destinations);
if (this.root.getNames() == null) {
this.root.setNames(getFactory().makeNames());
}
this.root.getNames().setDests(dests);
}
- output(stream);
- for (int count = 0; count < this.trailerObjects.size(); count++) {
- PDFObject o = (PDFObject)this.trailerObjects.get(count);
- setLocation(o.getObjectNumber() - 1, this.position);
- this.position += o.output(stream);
+ }
+
+ private void outputTrailerObjectsAndXref(OutputStream stream) throws IOException {
+ TrailerOutputHelper trailerOutputHelper = mayCompressStructureTreeElements()
+ ? new CompressedTrailerOutputHelper()
+ : new UncompressedTrailerOutputHelper();
+ if (structureTreeElements != null) {
+ trailerOutputHelper.outputStructureTreeElements(stream);
}
- /* output the xref table and increment the character position
- by the table's length */
- this.position += outputXref(stream);
-
- /* construct the trailer */
- StringBuffer pdf = new StringBuffer(128);
- pdf.append("trailer\n<<\n/Size ")
- .append(this.objectcount + 1)
- .append("\n/Root ")
- .append(this.root.referencePDF())
- .append("\n/Info ")
- .append(this.info.referencePDF())
- .append('\n');
-
- if (this.isEncryptionActive()) {
- pdf.append(this.encryption.getTrailerEntry());
- } else {
- byte[] fileID = getFileIDGenerator().getOriginalFileID();
- String fileIDAsString = PDFText.toHex(fileID);
- pdf.append("/ID [" + fileIDAsString + " " + fileIDAsString + "]");
+ streamIndirectObjects(trailerObjects, stream);
+ TrailerDictionary trailerDictionary = createTrailerDictionary();
+ long startxref = trailerOutputHelper.outputCrossReferenceObject(stream, trailerDictionary);
+ String trailer = "startxref\n" + startxref + "\n%%EOF\n";
+ stream.write(encode(trailer));
+ }
+
+ private boolean mayCompressStructureTreeElements() {
+ return accessibilityEnabled
+ && versionController.getPDFVersion().compareTo(Version.V1_5) >= 0;
+ }
+
+ private TrailerDictionary createTrailerDictionary() {
+ FileIDGenerator gen = getFileIDGenerator();
+ TrailerDictionary trailerDictionary = new TrailerDictionary(this)
+ .setRoot(root)
+ .setInfo(info)
+ .setFileID(gen.getOriginalFileID(), gen.getUpdatedFileID());
+ if (isEncryptionActive()) {
+ trailerDictionary.setEncryption(encryption);
}
+ return trailerDictionary;
+ }
- pdf.append("\n>>\nstartxref\n")
- .append(this.xref)
- .append("\n%%EOF\n");
+ private interface TrailerOutputHelper {
- /* write the trailer */
- stream.write(encode(pdf.toString()));
+ void outputStructureTreeElements(OutputStream stream) throws IOException;
+
+ /**
+ * @return the offset of the cross-reference object (the value of startxref)
+ */
+ long outputCrossReferenceObject(OutputStream stream, TrailerDictionary trailerDictionary)
+ throws IOException;
}
- /**
- * Write the xref table
- *
- * @param stream the OutputStream to write the xref table to
- * @return the number of characters written
- * @throws IOException in case of an error writing the result to
- * the parameter stream
- */
- private int outputXref(OutputStream stream) throws IOException {
-
- /* remember position of xref table */
- this.xref = this.position;
-
- /* construct initial part of xref */
- StringBuffer pdf = new StringBuffer(128);
- pdf.append("xref\n0 ");
- pdf.append(this.objectcount + 1);
- pdf.append("\n0000000000 65535 f \n");
-
- String s;
- String loc;
- for (int count = 0; count < this.location.size(); count++) {
- final String padding = "0000000000";
- s = this.location.get(count).toString();
- if (s.length() > 10) {
- throw new IOException("PDF file too large. PDF cannot grow beyond approx. 9.3GB.");
- }
+ private class UncompressedTrailerOutputHelper implements TrailerOutputHelper {
- /* contruct xref entry for object */
- loc = padding.substring(s.length()) + s;
+ public void outputStructureTreeElements(OutputStream stream)
+ throws IOException {
+ streamIndirectObjects(structureTreeElements, stream);
+ }
- /* append to xref table */
- pdf = pdf.append(loc).append(" 00000 n \n");
+ public long outputCrossReferenceObject(OutputStream stream,
+ TrailerDictionary trailerDictionary) throws IOException {
+ new CrossReferenceTable(trailerDictionary, position,
+ indirectObjectOffsets).output(stream);
+ return position;
}
+ }
+
+ private class CompressedTrailerOutputHelper implements TrailerOutputHelper {
+
+ private ObjectStreamManager structureTreeObjectStreams;
- /* write the xref table and return the character length */
- byte[] pdfBytes = encode(pdf.toString());
- stream.write(pdfBytes);
- return pdfBytes.length;
+ public void outputStructureTreeElements(OutputStream stream)
+ throws IOException {
+ assert structureTreeElements.size() > 0;
+ structureTreeObjectStreams = new ObjectStreamManager(PDFDocument.this);
+ for (PDFStructElem structElem : structureTreeElements) {
+ structureTreeObjectStreams.add(structElem);
+ }
+ }
+
+ public long outputCrossReferenceObject(OutputStream stream,
+ TrailerDictionary trailerDictionary) throws IOException {
+ // Outputting the object streams should not have created new indirect objects
+ assert objects.isEmpty();
+ new CrossReferenceStream(PDFDocument.this, ++objectcount, trailerDictionary, position,
+ indirectObjectOffsets,
+ structureTreeObjectStreams.getCompressedObjectReferences())
+ .output(stream);
+ return position;
+ }
}
long getCurrentFileSize() {
diff --git a/src/java/org/apache/fop/pdf/PDFEncryption.java b/src/java/org/apache/fop/pdf/PDFEncryption.java
index 277cf0a94..fcb56e50b 100644
--- a/src/java/org/apache/fop/pdf/PDFEncryption.java
+++ b/src/java/org/apache/fop/pdf/PDFEncryption.java
@@ -40,8 +40,10 @@ public interface PDFEncryption {
byte[] encrypt(byte[] data, PDFObject refObj);
/**
- * Returns the trailer entry for encryption.
- * @return the trailer entry
+ * Returns the /Encrypt entry in the file trailer dictionary.
+ *
+ * @return the string "/Encrypt n g R\n" where n and g are the number and generation
+ * of the document's encryption dictionary
*/
String getTrailerEntry();
}
diff --git a/src/java/org/apache/fop/pdf/PDFEncryptionJCE.java b/src/java/org/apache/fop/pdf/PDFEncryptionJCE.java
index c9b9c58ba..2ef3b93da 100644
--- a/src/java/org/apache/fop/pdf/PDFEncryptionJCE.java
+++ b/src/java/org/apache/fop/pdf/PDFEncryptionJCE.java
@@ -69,8 +69,9 @@ public final class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
? new Rev2Engine(encryptionSettings)
: new Rev3Engine(encryptionSettings);
initializationEngine.run();
- encryptionDictionary = createEncryptionDictionary(getObjectID(), permissions,
- initializationEngine.oValue, initializationEngine.uValue);
+ encryptionDictionary = createEncryptionDictionary(permissions,
+ initializationEngine.oValue,
+ initializationEngine.uValue);
}
private void determineEncryptionAlgorithm() {
@@ -91,18 +92,16 @@ public final class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
&& encryptionParams.isAllowPrintHq();
}
- private String createEncryptionDictionary(final String objectId, final int permissions,
- final byte[] oValue, final byte[] uValue) {
- return objectId
- + "<< /Filter /Standard\n"
+ private String createEncryptionDictionary(final int permissions, final byte[] oValue,
+ final byte[] uValue) {
+ return "<< /Filter /Standard\n"
+ "/V " + version + "\n"
+ "/R " + revision + "\n"
+ "/Length " + encryptionLength + "\n"
+ "/P " + permissions + "\n"
+ "/O " + PDFText.toHex(oValue) + "\n"
+ "/U " + PDFText.toHex(uValue) + "\n"
- + ">>\n"
- + "endobj\n";
+ + ">>";
}
}
@@ -488,14 +487,7 @@ public final class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
/** {@inheritDoc} */
public String getTrailerEntry() {
- PDFDocument doc = getDocumentSafely();
- FileIDGenerator gen = doc.getFileIDGenerator();
- return "/Encrypt " + getObjectNumber() + " "
- + getGeneration() + " R\n"
- + "/ID["
- + PDFText.toHex(gen.getOriginalFileID())
- + PDFText.toHex(gen.getUpdatedFileID())
- + "]\n";
+ return "/Encrypt " + getObjectNumber() + " " + getGeneration() + " R\n";
}
private static byte[] encryptWithKey(byte[] key, byte[] data) {
diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java
index a981dae88..2c347031f 100644
--- a/src/java/org/apache/fop/pdf/PDFFactory.java
+++ b/src/java/org/apache/fop/pdf/PDFFactory.java
@@ -913,35 +913,6 @@ public class PDFFactory {
}
/**
- * Creates and returns a StructTreeRoot object. Used for accessibility.
- * @param parentTree the value of the ParenTree entry
- * @return structure Tree Root element
- */
- public PDFStructTreeRoot makeStructTreeRoot(PDFParentTree parentTree) {
- PDFStructTreeRoot structTreeRoot = new PDFStructTreeRoot(parentTree);
- getDocument().assignObjectNumber(structTreeRoot);
- getDocument().addTrailerObject(structTreeRoot);
- getDocument().getRoot().setStructTreeRoot(structTreeRoot);
- return structTreeRoot;
- }
-
- /**
- * Creates and returns a StructElem object.
- *
- * @param structureType the structure type of the new element (value for the
- * S entry)
- * @param parent the parent of the new structure element in the structure
- * hierarchy
- * @return the newly created element
- */
- public PDFStructElem makeStructureElement(PDFName structureType, PDFObject parent) {
- PDFStructElem structElem = new PDFStructElem(parent, structureType);
- getDocument().assignObjectNumber(structElem);
- getDocument().addTrailerObject(structElem);
- return structElem;
- }
-
- /**
* Make a the head object of the name dictionary (the /Dests object).
*
* @param destinationList a list of PDFDestination instances
diff --git a/src/java/org/apache/fop/pdf/PDFFilterList.java b/src/java/org/apache/fop/pdf/PDFFilterList.java
index 3025b8788..3f26f454c 100644
--- a/src/java/org/apache/fop/pdf/PDFFilterList.java
+++ b/src/java/org/apache/fop/pdf/PDFFilterList.java
@@ -21,6 +21,7 @@ package org.apache.fop.pdf;
import java.io.IOException;
import java.io.OutputStream;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -47,7 +48,7 @@ public class PDFFilterList {
/** Key for the filter used for metadata */
public static final String METADATA_FILTER = "metadata";
- private List filters = new java.util.ArrayList();
+ private List<PDFFilter> filters = new java.util.ArrayList<PDFFilter>();
private boolean ignoreASCIIFilters = false;
@@ -197,6 +198,10 @@ public class PDFFilterList {
}
}
+ List<PDFFilter> getFilters() {
+ return Collections.unmodifiableList(filters);
+ }
+
/**
* Apply the filters to the data
* in the order given and return the /Filter and /DecodeParms
@@ -206,7 +211,7 @@ public class PDFFilterList {
* @return a String representing the filter list
*/
protected String buildFilterDictEntries() {
- if (filters != null && filters.size() > 0) {
+ if (filters.size() > 0) {
List names = new java.util.ArrayList();
List parms = new java.util.ArrayList();
@@ -229,7 +234,7 @@ public class PDFFilterList {
* @param dict the PDFDictionary to set the entries on
*/
protected void putFilterDictEntries(PDFDictionary dict) {
- if (filters != null && filters.size() > 0) {
+ if (filters.size() > 0) {
List names = new java.util.ArrayList();
List parms = new java.util.ArrayList();
@@ -358,7 +363,7 @@ public class PDFFilterList {
*/
public OutputStream applyFilters(OutputStream stream) throws IOException {
OutputStream out = stream;
- if (filters != null && !isDisableAllFilters()) {
+ if (!isDisableAllFilters()) {
for (int count = filters.size() - 1; count >= 0; count--) {
PDFFilter filter = (PDFFilter)filters.get(count);
out = filter.applyFilter(out);
diff --git a/src/java/org/apache/fop/pdf/PDFFont.java b/src/java/org/apache/fop/pdf/PDFFont.java
index 2808e5ba7..191fd223e 100644
--- a/src/java/org/apache/fop/pdf/PDFFont.java
+++ b/src/java/org/apache/fop/pdf/PDFFont.java
@@ -174,7 +174,7 @@ public class PDFFont extends PDFDictionary {
}
/** {@inheritDoc} */
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
validate();
return super.output(stream);
}
diff --git a/src/java/org/apache/fop/pdf/PDFFormXObject.java b/src/java/org/apache/fop/pdf/PDFFormXObject.java
index 2ccc17086..bc81a0a35 100644
--- a/src/java/org/apache/fop/pdf/PDFFormXObject.java
+++ b/src/java/org/apache/fop/pdf/PDFFormXObject.java
@@ -44,7 +44,7 @@ public class PDFFormXObject extends PDFXObject {
* @param resources the resource PDF reference
*/
public PDFFormXObject(int xnumber, PDFStream contents, PDFReference resources) {
- super();
+ super(contents.getDictionary());
put("Name", new PDFName("Form" + xnumber));
this.contents = contents;
@@ -160,7 +160,7 @@ public class PDFFormXObject extends PDFXObject {
}
/** {@inheritDoc} */
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
final int len = super.output(stream);
//Now that the data has been written, it can be discarded.
diff --git a/src/java/org/apache/fop/pdf/PDFFunction.java b/src/java/org/apache/fop/pdf/PDFFunction.java
index 9e93ebee8..44198105b 100644
--- a/src/java/org/apache/fop/pdf/PDFFunction.java
+++ b/src/java/org/apache/fop/pdf/PDFFunction.java
@@ -380,8 +380,7 @@ public class PDFFunction extends PDFObject {
int numberOfFunctions = 0;
int tempInt = 0;
StringBuffer p = new StringBuffer(256);
- p.append(getObjectID()
- + "<< \n/FunctionType " + this.functionType + " \n");
+ p.append("<< \n/FunctionType " + this.functionType + " \n");
// FunctionType 0
if (this.functionType == 0) {
@@ -482,15 +481,14 @@ public class PDFFunction extends PDFObject {
p.append("] \n");
}
}
- p.append(">> \n");
+ p.append(">>");
// stream representing the function
if (this.functionDataStream != null) {
- p.append("stream\n" + this.functionDataStream
- + "\nendstream\n");
+ p.append("\nstream\n" + this.functionDataStream
+ + "\nendstream");
}
- p.append("endobj\n");
// end of if FunctionType 0
} else if (this.functionType == 2) {
@@ -550,7 +548,7 @@ public class PDFFunction extends PDFObject {
+ PDFNumber.doubleOut(new Double(this.interpolationExponentN))
+ " \n");
- p.append(">> \nendobj\n");
+ p.append(">>");
} else if (this.functionType
== 3) { // fix this up when my eyes uncross
@@ -643,10 +641,7 @@ public class PDFFunction extends PDFObject {
}
}
- p.append("] \n");
-
-
- p.append(">> \nendobj\n");
+ p.append("]\n>>");
} else if (this.functionType
== 4) { // fix this up when my eyes uncross
// DOMAIN
@@ -681,15 +676,14 @@ public class PDFFunction extends PDFObject {
+ " \n");
}
- p.append(">> \n");
+ p.append(">>");
// stream representing the function
if (this.functionDataStream != null) {
- p.append("stream\n{ " + this.functionDataStream
- + " } \nendstream\n");
+ p.append("\nstream\n{ " + this.functionDataStream
+ + " }\nendstream");
}
- p.append("endobj\n");
}
diff --git a/src/java/org/apache/fop/pdf/PDFGState.java b/src/java/org/apache/fop/pdf/PDFGState.java
index fe57e39c2..7306218ae 100644
--- a/src/java/org/apache/fop/pdf/PDFGState.java
+++ b/src/java/org/apache/fop/pdf/PDFGState.java
@@ -149,12 +149,10 @@ public class PDFGState extends PDFObject {
*/
public String toPDFString() {
StringBuffer sb = new StringBuffer(64);
- sb.append(getObjectID());
sb.append("<<\n/Type /ExtGState\n");
appendVal(sb, GSTATE_ALPHA_NONSTROKE);
appendVal(sb, GSTATE_ALPHA_STROKE);
-
- sb.append(">>\nendobj\n");
+ sb.append(">>");
return sb.toString();
}
diff --git a/src/java/org/apache/fop/pdf/PDFGoTo.java b/src/java/org/apache/fop/pdf/PDFGoTo.java
index 0626f0fcd..784aa4f95 100644
--- a/src/java/org/apache/fop/pdf/PDFGoTo.java
+++ b/src/java/org/apache/fop/pdf/PDFGoTo.java
@@ -124,9 +124,7 @@ public class PDFGoTo extends PDFAction {
} else {
dest = "/D [" + this.pageReference + " " + destination + "]\n";
}
- return getObjectID()
- + "<< /Type /Action\n/S /GoTo\n" + dest
- + ">>\nendobj\n";
+ return "<< /Type /Action\n/S /GoTo\n" + dest + ">>";
}
/*
diff --git a/src/java/org/apache/fop/pdf/PDFGoToRemote.java b/src/java/org/apache/fop/pdf/PDFGoToRemote.java
index 93fbe47de..2dccdafce 100644
--- a/src/java/org/apache/fop/pdf/PDFGoToRemote.java
+++ b/src/java/org/apache/fop/pdf/PDFGoToRemote.java
@@ -106,7 +106,6 @@ public class PDFGoToRemote extends PDFAction {
*/
public String toPDFString() {
StringBuffer sb = new StringBuffer(64);
- sb.append(getObjectID());
sb.append("<<\n/S /GoToR\n/F ");
sb.append(pdfFileSpec.toString());
sb.append("\n");
@@ -121,7 +120,7 @@ public class PDFGoToRemote extends PDFAction {
sb.append("/NewWindow true");
}
- sb.append(" \n>>\nendobj\n");
+ sb.append("\n>>");
return sb.toString();
}
diff --git a/src/java/org/apache/fop/pdf/PDFICCBasedColorSpace.java b/src/java/org/apache/fop/pdf/PDFICCBasedColorSpace.java
index 87e8f5475..b86ba29f5 100644
--- a/src/java/org/apache/fop/pdf/PDFICCBasedColorSpace.java
+++ b/src/java/org/apache/fop/pdf/PDFICCBasedColorSpace.java
@@ -99,9 +99,7 @@ public class PDFICCBasedColorSpace extends PDFObject implements PDFColorSpace {
@Override
protected String toPDFString() {
StringBuffer sb = new StringBuffer(64);
- sb.append(getObjectID());
sb.append("[/ICCBased ").append(getICCStream().referencePDF()).append("]");
- sb.append("\nendobj\n");
return sb.toString();
}
diff --git a/src/java/org/apache/fop/pdf/PDFICCStream.java b/src/java/org/apache/fop/pdf/PDFICCStream.java
index 9002fcc94..33b81307b 100644
--- a/src/java/org/apache/fop/pdf/PDFICCStream.java
+++ b/src/java/org/apache/fop/pdf/PDFICCStream.java
@@ -64,7 +64,7 @@ public class PDFICCStream extends PDFStream {
* {@inheritDoc}
*/
@Override
- protected int output(java.io.OutputStream stream)
+ public int output(java.io.OutputStream stream)
throws java.io.IOException {
int length = super.output(stream);
this.cp = null; //Free ICC stream when it's not used anymore
diff --git a/src/java/org/apache/fop/pdf/PDFImageXObject.java b/src/java/org/apache/fop/pdf/PDFImageXObject.java
index 9ec8f1595..acab4c19c 100644
--- a/src/java/org/apache/fop/pdf/PDFImageXObject.java
+++ b/src/java/org/apache/fop/pdf/PDFImageXObject.java
@@ -61,7 +61,7 @@ public class PDFImageXObject extends PDFXObject {
* @throws IOException if there is an error writing the data
* @return the length of the data written
*/
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
int length = super.output(stream);
// let it gc
@@ -137,7 +137,7 @@ public class PDFImageXObject extends PDFXObject {
put("SMask", ref);
}
//Important: do this at the end so previous values can be overwritten.
- pdfimage.populateXObjectDictionary(this);
+ pdfimage.populateXObjectDictionary(getDictionary());
}
/** {@inheritDoc} */
diff --git a/src/java/org/apache/fop/pdf/PDFInfo.java b/src/java/org/apache/fop/pdf/PDFInfo.java
index 3f3fb3b46..d457c2888 100644
--- a/src/java/org/apache/fop/pdf/PDFInfo.java
+++ b/src/java/org/apache/fop/pdf/PDFInfo.java
@@ -169,7 +169,6 @@ public class PDFInfo extends PDFObject {
PDFProfile profile = getDocumentSafely().getProfile();
ByteArrayOutputStream bout = new ByteArrayOutputStream(128);
try {
- bout.write(encode(getObjectID()));
bout.write(encode("<<\n"));
if (title != null && title.length() > 0) {
bout.write(encode("/Title "));
@@ -229,7 +228,7 @@ public class PDFInfo extends PDFObject {
bout.write(encode("/Trapped /False\n"));
}
- bout.write(encode(">>\nendobj\n"));
+ bout.write(encode(">>"));
} catch (IOException ioe) {
log.error("Ignored I/O exception", ioe);
}
diff --git a/src/java/org/apache/fop/pdf/PDFLaunch.java b/src/java/org/apache/fop/pdf/PDFLaunch.java
index e62da5279..7d80ddb43 100644
--- a/src/java/org/apache/fop/pdf/PDFLaunch.java
+++ b/src/java/org/apache/fop/pdf/PDFLaunch.java
@@ -54,10 +54,9 @@ public class PDFLaunch extends PDFAction {
/** {@inheritDoc} */
public String toPDFString() {
StringBuffer sb = new StringBuffer(64);
- sb.append(getObjectID());
sb.append("<<\n/S /Launch\n/F ");
sb.append(externalFileSpec.toString());
- sb.append(" \n>>\nendobj\n");
+ sb.append("\n>>");
return sb.toString();
}
diff --git a/src/java/org/apache/fop/pdf/PDFLink.java b/src/java/org/apache/fop/pdf/PDFLink.java
index 934932648..ffec6f09c 100644
--- a/src/java/org/apache/fop/pdf/PDFLink.java
+++ b/src/java/org/apache/fop/pdf/PDFLink.java
@@ -92,15 +92,14 @@ public class PDFLink extends PDFObject {
f |= 1 << (5 - 1); //NoRotate, bit 5
fFlag = "/F " + f;
}
- String s = getObjectID()
- + "<< /Type /Annot\n" + "/Subtype /Link\n" + "/Rect [ "
+ String s = "<< /Type /Annot\n" + "/Subtype /Link\n" + "/Rect [ "
+ (ulx) + " " + (uly) + " "
+ (brx) + " " + (bry) + " ]\n" + "/C [ "
+ this.color + " ]\n" + "/Border [ 0 0 0 ]\n" + "/A "
+ this.action.getAction() + "\n" + "/H /I\n"
+ (this.structParent != null
? "/StructParent " + this.structParent.toString() + "\n" : "")
- + fFlag + "\n>>\nendobj\n";
+ + fFlag + "\n>>";
return s;
}
diff --git a/src/java/org/apache/fop/pdf/PDFMetadata.java b/src/java/org/apache/fop/pdf/PDFMetadata.java
index b9612d11b..9b1b8165b 100644
--- a/src/java/org/apache/fop/pdf/PDFMetadata.java
+++ b/src/java/org/apache/fop/pdf/PDFMetadata.java
@@ -79,7 +79,7 @@ public class PDFMetadata extends PDFStream {
* byte arrays around so much
* {@inheritDoc}
*/
- protected int output(java.io.OutputStream stream)
+ public int output(java.io.OutputStream stream)
throws java.io.IOException {
int length = super.output(stream);
this.xmpMetadata = null; //Release DOM when it's not used anymore
diff --git a/src/java/org/apache/fop/pdf/PDFName.java b/src/java/org/apache/fop/pdf/PDFName.java
index 7fa6842fa..23294cc54 100644
--- a/src/java/org/apache/fop/pdf/PDFName.java
+++ b/src/java/org/apache/fop/pdf/PDFName.java
@@ -108,22 +108,11 @@ public class PDFName extends PDFObject {
return name.hashCode();
}
-
- /** {@inheritDoc} */
@Override
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
- if (hasObjectNumber()) {
- textBuffer.append(getObjectID());
- }
-
textBuffer.append(toString());
-
- if (hasObjectNumber()) {
- textBuffer.append("\nendobj\n");
- }
-
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
diff --git a/src/java/org/apache/fop/pdf/PDFNumber.java b/src/java/org/apache/fop/pdf/PDFNumber.java
index 5bc648ced..95242305c 100644
--- a/src/java/org/apache/fop/pdf/PDFNumber.java
+++ b/src/java/org/apache/fop/pdf/PDFNumber.java
@@ -85,13 +85,7 @@ public class PDFNumber extends PDFObject {
"The number of this PDFNumber must not be empty");
}
StringBuffer sb = new StringBuffer(64);
- if (hasObjectNumber()) {
- sb.append(getObjectID());
- }
sb.append(doubleOut(getNumber().doubleValue(), 10));
- if (hasObjectNumber()) {
- sb.append("\nendobj\n");
- }
return sb.toString();
}
diff --git a/src/java/org/apache/fop/pdf/PDFNumsArray.java b/src/java/org/apache/fop/pdf/PDFNumsArray.java
index ecd301647..e9e1855b0 100644
--- a/src/java/org/apache/fop/pdf/PDFNumsArray.java
+++ b/src/java/org/apache/fop/pdf/PDFNumsArray.java
@@ -88,13 +88,9 @@ public class PDFNumsArray extends PDFObject {
/** {@inheritDoc} */
@Override
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
- if (hasObjectNumber()) {
- textBuffer.append(getObjectID());
- }
-
textBuffer.append('[');
boolean first = true;
for (Map.Entry<Integer, Object> entry : this.map.entrySet()) {
@@ -107,11 +103,6 @@ public class PDFNumsArray extends PDFObject {
formatObject(entry.getValue(), cout, textBuffer);
}
textBuffer.append(']');
-
- if (hasObjectNumber()) {
- textBuffer.append("\nendobj\n");
- }
-
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
diff --git a/src/java/org/apache/fop/pdf/PDFObject.java b/src/java/org/apache/fop/pdf/PDFObject.java
index 5abb5a142..1b9c4eea7 100644
--- a/src/java/org/apache/fop/pdf/PDFObject.java
+++ b/src/java/org/apache/fop/pdf/PDFObject.java
@@ -204,7 +204,7 @@ public abstract class PDFObject implements PDFWritable {
* @throws IOException if there is an error writing to the stream
* @return the number of bytes written
*/
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
byte[] pdf = this.toPDF();
stream.write(pdf);
return pdf.length;
diff --git a/src/java/org/apache/fop/pdf/PDFOutline.java b/src/java/org/apache/fop/pdf/PDFOutline.java
index 66116c681..61c562548 100644
--- a/src/java/org/apache/fop/pdf/PDFOutline.java
+++ b/src/java/org/apache/fop/pdf/PDFOutline.java
@@ -131,7 +131,6 @@ public class PDFOutline extends PDFObject {
protected byte[] toPDF() {
ByteArrayOutputStream bout = new ByteArrayOutputStream(128);
try {
- bout.write(encode(getObjectID()));
bout.write(encode("<<"));
if (parent == null) {
// root Outlines object
@@ -164,7 +163,7 @@ public class PDFOutline extends PDFObject {
bout.write(encode(" /A " + actionRef + "\n"));
}
}
- bout.write(encode(">> endobj\n"));
+ bout.write(encode(">>"));
} catch (IOException ioe) {
log.error("Ignored I/O exception", ioe);
}
diff --git a/src/java/org/apache/fop/pdf/PDFOutputIntent.java b/src/java/org/apache/fop/pdf/PDFOutputIntent.java
index ea073829b..1c0373944 100644
--- a/src/java/org/apache/fop/pdf/PDFOutputIntent.java
+++ b/src/java/org/apache/fop/pdf/PDFOutputIntent.java
@@ -130,7 +130,6 @@ public class PDFOutputIntent extends PDFObject {
public byte[] toPDF() {
ByteArrayOutputStream bout = new ByteArrayOutputStream(128);
try {
- bout.write(encode(getObjectID()));
bout.write(encode("<<\n"));
bout.write(encode("/Type /OutputIntent\n"));
@@ -164,7 +163,7 @@ public class PDFOutputIntent extends PDFObject {
bout.write(encode("/DestOutputProfile " + destOutputProfile.referencePDF() + "\n"));
}
- bout.write(encode(">>\nendobj\n"));
+ bout.write(encode(">>"));
} catch (IOException ioe) {
log.error("Ignored I/O exception", ioe);
}
diff --git a/src/java/org/apache/fop/pdf/PDFPages.java b/src/java/org/apache/fop/pdf/PDFPages.java
index 61d860eaa..98c293a97 100644
--- a/src/java/org/apache/fop/pdf/PDFPages.java
+++ b/src/java/org/apache/fop/pdf/PDFPages.java
@@ -109,10 +109,9 @@ public class PDFPages extends PDFObject {
*/
public String toPDFString() {
StringBuffer sb = new StringBuffer(64);
- sb.append(getObjectID())
- .append("<< /Type /Pages\n/Count ")
- .append(this.getCount())
- .append("\n/Kids [");
+ sb.append("<< /Type /Pages\n/Count ")
+ .append(this.getCount())
+ .append("\n/Kids [");
for (int i = 0; i < kids.size(); i++) {
Object kid = kids.get(i);
if (kid == null) {
@@ -120,7 +119,7 @@ public class PDFPages extends PDFObject {
}
sb.append(kid).append(" ");
}
- sb.append("] >>\nendobj\n");
+ sb.append("] >>");
return sb.toString();
}
diff --git a/src/java/org/apache/fop/pdf/PDFPattern.java b/src/java/org/apache/fop/pdf/PDFPattern.java
index 378b1cf8b..88a2ff492 100644
--- a/src/java/org/apache/fop/pdf/PDFPattern.java
+++ b/src/java/org/apache/fop/pdf/PDFPattern.java
@@ -210,13 +210,12 @@ public class PDFPattern extends PDFPathPaint {
* @throws IOException if there is an error writing to the stream
* @return the PDF string.
*/
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
int vectorSize = 0;
int tempInt = 0;
byte[] buffer;
StringBuffer p = new StringBuffer(64);
- p.append(getObjectID());
p.append("<< \n/Type /Pattern \n");
if (this.resources != null) {
@@ -323,10 +322,6 @@ public class PDFPattern extends PDFPathPaint {
length += pdfStream.outputStreamData(encodedStream, stream);
}
- buffer = encode("\nendobj\n");
- stream.write(buffer);
- length += buffer.length;
-
return length;
}
diff --git a/src/java/org/apache/fop/pdf/PDFResources.java b/src/java/org/apache/fop/pdf/PDFResources.java
index 70f9af504..df8647bf4 100644
--- a/src/java/org/apache/fop/pdf/PDFResources.java
+++ b/src/java/org/apache/fop/pdf/PDFResources.java
@@ -192,8 +192,8 @@ public class PDFResources extends PDFDictionary {
return cs;
}
- /** {@inheritDoc} */
- protected int output(OutputStream stream) throws IOException {
+ @Override
+ public int output(OutputStream stream) throws IOException {
populateDictionary();
return super.output(stream);
}
diff --git a/src/java/org/apache/fop/pdf/PDFRoot.java b/src/java/org/apache/fop/pdf/PDFRoot.java
index 81b93b159..e74c77478 100644
--- a/src/java/org/apache/fop/pdf/PDFRoot.java
+++ b/src/java/org/apache/fop/pdf/PDFRoot.java
@@ -76,7 +76,7 @@ public class PDFRoot extends PDFDictionary {
}
/** {@inheritDoc} */
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
getDocument().getProfile().verifyTaggedPDF();
return super.output(stream);
}
diff --git a/src/java/org/apache/fop/pdf/PDFShading.java b/src/java/org/apache/fop/pdf/PDFShading.java
index 2f955b850..90953968c 100644
--- a/src/java/org/apache/fop/pdf/PDFShading.java
+++ b/src/java/org/apache/fop/pdf/PDFShading.java
@@ -342,8 +342,7 @@ public class PDFShading extends PDFObject {
int vectorSize;
int tempInt;
StringBuffer p = new StringBuffer(128);
- p.append(getObjectID()
- + "<< \n/ShadingType " + this.shadingType + " \n");
+ p.append("<<\n/ShadingType " + this.shadingType + " \n");
if (this.colorSpace != null) {
p.append("/ColorSpace /"
+ this.colorSpace.getName() + " \n");
@@ -528,7 +527,7 @@ public class PDFShading extends PDFObject {
}
- p.append(">> \nendobj\n");
+ p.append(">>");
return (p.toString());
}
diff --git a/src/java/org/apache/fop/pdf/PDFStream.java b/src/java/org/apache/fop/pdf/PDFStream.java
index 5f74a2613..a0b990ec5 100644
--- a/src/java/org/apache/fop/pdf/PDFStream.java
+++ b/src/java/org/apache/fop/pdf/PDFStream.java
@@ -21,6 +21,7 @@ package org.apache.fop.pdf;
import java.io.IOException;
import java.io.OutputStream;
+import java.io.OutputStreamWriter;
import java.io.Writer;
/**
@@ -44,16 +45,33 @@ public class PDFStream extends AbstractPDFStream {
* Create an empty stream object
*/
public PDFStream() {
- super();
+ setUp();
+ }
+
+ public PDFStream(PDFDictionary dictionary) {
+ super(dictionary);
+ setUp();
+ }
+
+ public PDFStream(PDFDictionary dictionary, boolean encodeOnTheFly) {
+ super(dictionary, encodeOnTheFly);
+ setUp();
+ }
+
+ public PDFStream(boolean encodeOnTheFly) {
+ super(encodeOnTheFly);
+ setUp();
+ }
+
+ private void setUp() {
try {
data = StreamCacheFactory.getInstance().createStreamCache();
- this.streamWriter = new java.io.OutputStreamWriter(
+ this.streamWriter = new OutputStreamWriter(
getBufferOutputStream(), PDFDocument.ENCODING);
//Buffer to minimize calls to the converter
this.streamWriter = new java.io.BufferedWriter(this.streamWriter);
- } catch (IOException ex) {
- //TODO throw the exception and catch it elsewhere
- ex.printStackTrace();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
}
@@ -136,7 +154,7 @@ public class PDFStream extends AbstractPDFStream {
/**
* {@inheritDoc}
*/
- protected int output(OutputStream stream) throws IOException {
+ public int output(OutputStream stream) throws IOException {
final int len = super.output(stream);
//Now that the data has been written, it can be discarded.
diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java
index e35a860d9..90a41fb72 100644
--- a/src/java/org/apache/fop/pdf/PDFStructElem.java
+++ b/src/java/org/apache/fop/pdf/PDFStructElem.java
@@ -31,7 +31,7 @@ import org.apache.fop.util.LanguageTags;
/**
* Class representing a PDF Structure Element.
*/
-public class PDFStructElem extends PDFDictionary implements StructureTreeElement {
+public class PDFStructElem extends PDFDictionary implements StructureTreeElement, CompressedObject {
private PDFStructElem parentElement;
diff --git a/src/java/org/apache/fop/pdf/PDFT1Stream.java b/src/java/org/apache/fop/pdf/PDFT1Stream.java
index d723625eb..2bae5dca3 100644
--- a/src/java/org/apache/fop/pdf/PDFT1Stream.java
+++ b/src/java/org/apache/fop/pdf/PDFT1Stream.java
@@ -46,7 +46,7 @@ public class PDFT1Stream extends AbstractPDFFontStream {
* byte arrays around so much
* {@inheritDoc}
*/
- protected int output(java.io.OutputStream stream)
+ public int output(java.io.OutputStream stream)
throws java.io.IOException {
if (pfb == null) {
throw new IllegalStateException("pfb must not be null at this point");
diff --git a/src/java/org/apache/fop/pdf/PDFTTFStream.java b/src/java/org/apache/fop/pdf/PDFTTFStream.java
index 643ddb1e8..998e14f28 100644
--- a/src/java/org/apache/fop/pdf/PDFTTFStream.java
+++ b/src/java/org/apache/fop/pdf/PDFTTFStream.java
@@ -53,7 +53,7 @@ public class PDFTTFStream extends AbstractPDFFontStream {
* byte arrays around so much
* {@inheritDoc}
*/
- protected int output(java.io.OutputStream stream)
+ public int output(java.io.OutputStream stream)
throws java.io.IOException {
if (log.isDebugEnabled()) {
log.debug("Writing " + origLength + " bytes of TTF font data");
diff --git a/src/java/org/apache/fop/pdf/PDFText.java b/src/java/org/apache/fop/pdf/PDFText.java
index 9566f60da..3cddfe426 100644
--- a/src/java/org/apache/fop/pdf/PDFText.java
+++ b/src/java/org/apache/fop/pdf/PDFText.java
@@ -60,11 +60,9 @@ public class PDFText extends PDFObject {
"The text of this PDFText must not be empty");
}
StringBuffer sb = new StringBuffer(64);
- sb.append(getObjectID());
sb.append("(");
sb.append(escapeText(getText()));
sb.append(")");
- sb.append("\nendobj\n");
return sb.toString();
}
diff --git a/src/java/org/apache/fop/pdf/PDFUri.java b/src/java/org/apache/fop/pdf/PDFUri.java
index a6124ec03..b3d377ff1 100644
--- a/src/java/org/apache/fop/pdf/PDFUri.java
+++ b/src/java/org/apache/fop/pdf/PDFUri.java
@@ -55,8 +55,7 @@ public class PDFUri extends PDFAction {
/** {@inheritDoc} */
public String toPDFString() {
//TODO Convert this class into a dictionary
- return getObjectID() + getDictString() + "\nendobj\n";
- //throw new UnsupportedOperationException("This method should not be called");
+ return getDictString();
}
}
diff --git a/src/java/org/apache/fop/pdf/PDFXObject.java b/src/java/org/apache/fop/pdf/PDFXObject.java
index d1ce6d75e..c2b702650 100644
--- a/src/java/org/apache/fop/pdf/PDFXObject.java
+++ b/src/java/org/apache/fop/pdf/PDFXObject.java
@@ -41,6 +41,10 @@ public abstract class PDFXObject extends AbstractPDFStream {
super();
}
+ protected PDFXObject(PDFDictionary dictionary) {
+ super(dictionary);
+ }
+
/**
* Returns the XObject's name.
* @return the name of the XObject
diff --git a/src/java/org/apache/fop/pdf/Version.java b/src/java/org/apache/fop/pdf/Version.java
index 0df63d312..4bdc7a1b4 100644
--- a/src/java/org/apache/fop/pdf/Version.java
+++ b/src/java/org/apache/fop/pdf/Version.java
@@ -48,12 +48,13 @@ public enum Version {
}
/**
- * Given the PDF version as a String, returns the corresponding enumerated type. The String
- * should be in the format "1.x" for PDF v1.x.
+ * Given the PDF version as a String, returns the corresponding enumerated type. The
+ * String should be in the format "1.x" for PDF v1.x.
*
* @param version a version number
* @return the corresponding Version instance
- * @throws IllegalArgumentException if the argument does not correspond to any existing PDF version
+ * @throws IllegalArgumentException if the argument does not correspond to any
+ * existing PDF version
*/
public static Version getValueOf(String version) {
for (Version pdfVersion : Version.values()) {
diff --git a/src/java/org/apache/fop/pdf/xref/CompressedObjectReference.java b/src/java/org/apache/fop/pdf/xref/CompressedObjectReference.java
new file mode 100644
index 000000000..eb619fcc6
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/xref/CompressedObjectReference.java
@@ -0,0 +1,66 @@
+/*
+ * 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.xref;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * A reference to an indirect object stored in an object stream. Contains the relevant
+ * information to add to a cross-reference stream.
+ */
+public class CompressedObjectReference implements ObjectReference {
+
+ private final int objectNumber;
+
+ private final int objectStreamNumber;
+
+ private final int index;
+
+ /**
+ * Creates a new reference.
+ *
+ * @param objectNumber the number of the compressed object being referenced
+ * @param objectStreamNumber the number of the object stream in which the compressed
+ * object is to be found
+ * @param index the index of the compressed object in the object stream
+ */
+ public CompressedObjectReference(int objectNumber, int objectStreamNumber, int index) {
+ this.objectNumber = objectNumber;
+ this.objectStreamNumber = objectStreamNumber;
+ this.index = index;
+ }
+
+ public void output(DataOutputStream out) throws IOException {
+ out.write(2);
+ out.writeLong(objectStreamNumber);
+ out.write(0);
+ out.write(index);
+ }
+
+ public int getObjectNumber() {
+ return objectNumber;
+ }
+
+ public int getObjectStreamNumber() {
+ return objectStreamNumber;
+ }
+
+}
diff --git a/src/java/org/apache/fop/pdf/xref/CrossReferenceObject.java b/src/java/org/apache/fop/pdf/xref/CrossReferenceObject.java
new file mode 100644
index 000000000..3db50eca9
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/xref/CrossReferenceObject.java
@@ -0,0 +1,46 @@
+/*
+ * 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.xref;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A representation of the cross-reference data to be output at the end of a PDF file.
+ */
+public abstract class CrossReferenceObject {
+
+ protected final TrailerDictionary trailerDictionary;
+
+ protected final long startxref;
+
+ CrossReferenceObject(TrailerDictionary trailerDictionary, long startxref) {
+ this.trailerDictionary = trailerDictionary;
+ this.startxref = startxref;
+ }
+
+ /**
+ * Writes the cross reference data to a PDF stream
+ *
+ * @param stream the stream to write the cross reference to
+ * @throws IOException if an I/O exception occurs while writing the data
+ */
+ public abstract void output(OutputStream stream) throws IOException;
+}
diff --git a/src/java/org/apache/fop/pdf/xref/CrossReferenceStream.java b/src/java/org/apache/fop/pdf/xref/CrossReferenceStream.java
new file mode 100644
index 000000000..32c31573f
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/xref/CrossReferenceStream.java
@@ -0,0 +1,107 @@
+/*
+ * 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.xref;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.fop.pdf.PDFArray;
+import org.apache.fop.pdf.PDFDictionary;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFFilterList;
+import org.apache.fop.pdf.PDFName;
+import org.apache.fop.pdf.PDFStream;
+
+/**
+ * A cross-reference stream, as described in Section 3.4.7 of the PDF 1.5 Reference.
+ */
+public class CrossReferenceStream extends CrossReferenceObject {
+
+ private static final PDFName XREF = new PDFName("XRef");
+
+ private final PDFDocument document;
+
+ private final int objectNumber;
+
+ private final List<ObjectReference> objectReferences;
+
+ public CrossReferenceStream(PDFDocument document,
+ int objectNumber,
+ TrailerDictionary trailerDictionary,
+ long startxref,
+ List<Long> uncompressedObjectReferences,
+ List<CompressedObjectReference> compressedObjectReferences) {
+ super(trailerDictionary, startxref);
+ this.document = document;
+ this.objectNumber = objectNumber;
+ this.objectReferences = new ArrayList<ObjectReference>(uncompressedObjectReferences.size());
+ for (Long offset : uncompressedObjectReferences) {
+ objectReferences.add(offset == null ? null : new UncompressedObjectReference(offset));
+ }
+ for (CompressedObjectReference ref : compressedObjectReferences) {
+ this.objectReferences.set(ref.getObjectNumber() - 1, ref);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void output(OutputStream stream) throws IOException {
+ populateDictionary();
+ PDFStream helperStream = new PDFStream(trailerDictionary.getDictionary(), false) {
+
+ @Override
+ protected void setupFilterList() {
+ PDFFilterList filterList = getFilterList();
+ assert !filterList.isInitialized();
+ filterList.addDefaultFilters(document.getFilterMap(), getDefaultFilterName());
+ }
+
+ };
+ helperStream.setObjectNumber(objectNumber);
+ helperStream.setDocument(document);
+ ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
+ DataOutputStream data = new DataOutputStream(byteArray);
+ addFreeEntryForObject0(data);
+ for (ObjectReference objectReference : objectReferences) {
+ assert objectReference != null;
+ objectReference.output(data);
+ }
+ new UncompressedObjectReference(startxref).output(data);
+ data.close();
+ helperStream.setData(byteArray.toByteArray());
+ PDFDocument.outputIndirectObject(helperStream, stream);
+ }
+
+ private void populateDictionary() throws IOException {
+ int objectCount = objectReferences.size() + 1;
+ PDFDictionary dictionary = trailerDictionary.getDictionary();
+ dictionary.put("/Type", XREF);
+ dictionary.put("/Size", objectCount + 1);
+ dictionary.put("/W", new PDFArray(1, 8, 2));
+ }
+
+ private void addFreeEntryForObject0(DataOutputStream data) throws IOException {
+ data.write(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xff, (byte) 0xff});
+ }
+
+}
diff --git a/src/java/org/apache/fop/pdf/xref/CrossReferenceTable.java b/src/java/org/apache/fop/pdf/xref/CrossReferenceTable.java
new file mode 100644
index 000000000..41a1146ca
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/xref/CrossReferenceTable.java
@@ -0,0 +1,73 @@
+/*
+ * 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.xref;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.apache.fop.pdf.PDFDictionary;
+import org.apache.fop.pdf.PDFDocument;
+
+/**
+ * A cross-reference table, as described in Section 3.4.3 of the PDF 1.5 Reference.
+ */
+public class CrossReferenceTable extends CrossReferenceObject {
+
+ private final List<Long> objectReferences;
+
+ private final StringBuilder pdf = new StringBuilder(256);
+
+ public CrossReferenceTable(TrailerDictionary trailerDictionary, long startxref,
+ List<Long> location) {
+ super(trailerDictionary, startxref);
+ this.objectReferences = location;
+ }
+
+ public void output(OutputStream stream) throws IOException {
+ outputXref();
+ writeTrailer(stream);
+ }
+
+ private void outputXref() throws IOException {
+ pdf.append("xref\n0 ");
+ pdf.append(objectReferences.size() + 1);
+ pdf.append("\n0000000000 65535 f \n");
+ for (Long objectReference : objectReferences) {
+ final String padding = "0000000000";
+ String s = String.valueOf(objectReference);
+ if (s.length() > 10) {
+ throw new IOException("PDF file too large."
+ + " PDF 1.4 cannot grow beyond approx. 9.3GB.");
+ }
+ String loc = padding.substring(s.length()) + s;
+ pdf.append(loc).append(" 00000 n \n");
+ }
+ }
+
+ private void writeTrailer(OutputStream stream) throws IOException {
+ pdf.append("trailer\n");
+ stream.write(PDFDocument.encode(pdf.toString()));
+ PDFDictionary dictionary = trailerDictionary.getDictionary();
+ dictionary.put("/Size", objectReferences.size() + 1);
+ dictionary.output(stream);
+ }
+
+}
diff --git a/src/java/org/apache/fop/pdf/xref/ObjectReference.java b/src/java/org/apache/fop/pdf/xref/ObjectReference.java
new file mode 100644
index 000000000..894a66ce6
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/xref/ObjectReference.java
@@ -0,0 +1,39 @@
+/*
+ * 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.xref;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * A reference to an indirect object.
+ */
+interface ObjectReference {
+
+ /**
+ * Outputs this reference to the given stream, in the cross-reference stream format.
+ * For example, a object may output the bytes 01 00 00 00 00 00 00 01 ff 00 to
+ * indicate a non-compressed object (01), at offset 511 from the beginning of the file
+ * (00 00 00 00 00 00 01 ff), of generation number 0 (00).
+ *
+ * @param out the stream to which to output the reference
+ */
+ void output(DataOutputStream out) throws IOException;
+}
diff --git a/src/java/org/apache/fop/pdf/xref/TrailerDictionary.java b/src/java/org/apache/fop/pdf/xref/TrailerDictionary.java
new file mode 100644
index 000000000..d5d62522f
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/xref/TrailerDictionary.java
@@ -0,0 +1,94 @@
+/*
+ * 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.xref;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.fop.pdf.PDFArray;
+import org.apache.fop.pdf.PDFDictionary;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFEncryption;
+import org.apache.fop.pdf.PDFInfo;
+import org.apache.fop.pdf.PDFRoot;
+import org.apache.fop.pdf.PDFText;
+import org.apache.fop.pdf.PDFWritable;
+
+/**
+ * A data class representing entries of the file trailer dictionary.
+ */
+public class TrailerDictionary {
+
+ private final PDFDictionary dictionary;
+
+ public TrailerDictionary(PDFDocument pdfDocument) {
+ this.dictionary = new PDFDictionary();
+ this.dictionary.setDocument(pdfDocument);
+ }
+
+ /** Sets the value of the Root entry. */
+ public TrailerDictionary setRoot(PDFRoot root) {
+ dictionary.put("/Root", root);
+ return this;
+ }
+
+ /** Sets the value of the Info entry. */
+ public TrailerDictionary setInfo(PDFInfo info) {
+ dictionary.put("/Info", info);
+ return this;
+ }
+
+ /** Sets the value of the Encrypt entry. */
+ public TrailerDictionary setEncryption(PDFEncryption encryption) {
+ dictionary.put("/Encrypt", encryption);
+ return this;
+ }
+
+ /** Sets the value of the ID entry. */
+ public TrailerDictionary setFileID(byte[] originalFileID, byte[] updatedFileID) {
+ // TODO this is ugly! Used to circumvent the fact that the file ID will be
+ // encrypted if directly stored as a byte array
+ class FileID implements PDFWritable {
+
+ private final byte[] fileID;
+
+ FileID(byte[] id) {
+ fileID = id;
+ }
+
+ public void outputInline(OutputStream out, StringBuilder textBuffer)
+ throws IOException {
+ PDFDocument.flushTextBuffer(textBuffer, out);
+ String hex = PDFText.toHex(fileID, true);
+ byte[] encoded = hex.getBytes("US-ASCII");
+ out.write(encoded);
+ }
+
+ }
+ PDFArray fileID = new PDFArray(new FileID(originalFileID), new FileID(updatedFileID));
+ dictionary.put("/ID", fileID);
+ return this;
+ }
+
+ PDFDictionary getDictionary() {
+ return dictionary;
+ }
+
+}
diff --git a/src/java/org/apache/fop/pdf/xref/UncompressedObjectReference.java b/src/java/org/apache/fop/pdf/xref/UncompressedObjectReference.java
new file mode 100644
index 000000000..a54ec62e7
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/xref/UncompressedObjectReference.java
@@ -0,0 +1,48 @@
+/*
+ * 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.xref;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * A reference to an indirect object that is not stored in an object stream.
+ */
+class UncompressedObjectReference implements ObjectReference {
+
+ final long offset;
+
+ /**
+ * Creates a new reference.
+ *
+ * @param offset offset of the object from the beginning of the PDF file
+ */
+ UncompressedObjectReference(long offset) {
+ this.offset = offset;
+ }
+
+ public void output(DataOutputStream out) throws IOException {
+ out.write(1);
+ out.writeLong(offset);
+ out.write(0);
+ out.write(0);
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
index 88a6e9c22..1c9f9b49d 100644
--- a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
+++ b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
@@ -95,15 +95,15 @@ class PDFLogicalStructureHandler {
*/
PDFLogicalStructureHandler(PDFDocument pdfDoc) {
this.pdfDoc = pdfDoc;
- PDFStructTreeRoot structTreeRoot = pdfDoc.getFactory().makeStructTreeRoot(parentTree);
- rootStructureElement = pdfDoc.getFactory().makeStructureElement(
+ PDFStructTreeRoot structTreeRoot = pdfDoc.makeStructTreeRoot(parentTree);
+ rootStructureElement = pdfDoc.makeStructureElement(
FOToPDFRoleMap.mapFormattingObject("root", structTreeRoot), structTreeRoot);
structTreeRoot.addKid(rootStructureElement);
}
PDFStructElem createPageSequence(Locale language) {
- PDFStructElem structElemPart = pdfDoc.getFactory().makeStructureElement(
+ PDFStructElem structElemPart = pdfDoc.makeStructureElement(
FOToPDFRoleMap.mapFormattingObject("page-sequence", rootStructureElement),
rootStructureElement);
rootStructureElement.addKid(structElemPart);
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
index 83f6ccab6..53d259677 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
@@ -385,8 +385,8 @@ class PDFRenderingUtil implements PDFConfigurationConstants {
if (maxPDFVersion == null) {
this.pdfDoc = new PDFDocument(producer);
} else {
- VersionController controller =
- VersionController.getFixedVersionController(maxPDFVersion);
+ VersionController controller
+ = VersionController.getFixedVersionController(maxPDFVersion);
this.pdfDoc = new PDFDocument(producer, controller);
}
updateInfo();
@@ -411,6 +411,9 @@ class PDFRenderingUtil implements PDFConfigurationConstants {
log.debug("PDF/A is active. Conformance Level: " + pdfAMode);
addPDFA1OutputIntent();
}
+
+ this.pdfDoc.enableAccessibility(userAgent.isAccessibilityEnabled());
+
return this.pdfDoc;
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java
index 11eba4ea4..2a2a4a392 100644
--- a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java
+++ b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java
@@ -65,7 +65,7 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler {
PDFStructElem parent = ancestors.getFirst();
String role = attributes.getValue("role");
PDFStructElem created;
- created = pdfFactory.makeStructureElement(
+ created = pdfFactory.getDocument().makeStructureElement(
FOToPDFRoleMap.mapFormattingObject(name, role, parent, eventBroadcaster), parent);
parent.addKid(created);
ancestors.addFirst(created);
@@ -84,7 +84,7 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler {
PDFStructElem parent = ancestors.getFirst();
String role = attributes.getValue("role");
PDFStructElem created;
- created = pdfFactory.makeStructureElement(
+ created = pdfFactory.getDocument().makeStructureElement(
FOToPDFRoleMap.mapFormattingObject(name, role, parent, eventBroadcaster), parent);
parent.addKid(created);
String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text");
@@ -104,7 +104,7 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler {
if ("#PCDATA".equals(name)) {
created = new PDFStructElem.Placeholder(parent, name);
} else {
- created = pdfFactory.makeStructureElement(
+ created = pdfFactory.getDocument().makeStructureElement(
FOToPDFRoleMap.mapFormattingObject(name, role, parent,
eventBroadcaster), parent);
}