import java.io.IOException;
import java.io.OutputStream;
+import java.io.Writer;
import org.apache.commons.io.output.CountingOutputStream;
+
import org.apache.fop.util.CloseBlockerOutputStream;
/**
* {@inheritDoc}
*/
protected int output(OutputStream stream) throws IOException {
- int length = 0;
setupFilterList();
+
+ CountingOutputStream cout = new CountingOutputStream(stream);
+ Writer writer = PDFDocument.getWriterFor(cout);
+ writer.write(getObjectID());
+ //int length = 0;
StreamCache encodedStream = null;
PDFNumber refLength = null;
lengthEntry = new Integer(encodedStream.getSize() + 1);
}
- byte[] p = encode(buildStreamDict(lengthEntry));
- stream.write(p);
- length += p.length;
+ populateStreamDict(lengthEntry);
+ writeDictionary(cout, writer);
//Send encoded stream to target OutputStream
+ writer.flush();
if (encodedStream == null) {
- int bytesWritten = encodeAndWriteStream(stream, refLength);
- length += bytesWritten;
+ encodeAndWriteStream(cout, refLength);
} else {
- length += outputStreamData(encodedStream, stream);
+ outputStreamData(encodedStream, cout);
encodedStream.clear(); //Encoded stream can now be discarded
}
- p = encode("\nendobj\n");
- stream.write(p);
- length += p.length;
- return length;
- }
-
- /**
- * Constructs the dictionary for the stream. Override this method if you
- * need additional entries.
- * @param lengthEntry value for the /Length entry
- * @return the newly constructed dictionary
- */
- protected String buildStreamDict(Object lengthEntry) {
- StringBuffer sb = new StringBuffer();
- sb.append(getObjectID());
- populateStreamDict(lengthEntry);
-
- writeDictionary(sb);
- return sb.toString();
+ writer.write("\nendobj\n");
+ writer.flush();
+ return cout.getCount();
}
/**
return null;
}
- /**
- * Get the soft mask reference for this image.
- *
- * @return the soft mask reference if any
- */
- public String getSoftMask() {
- return maskRef.toInlinePDFString();
- }
-
/** {@inheritDoc} */
public PDFReference getSoftMaskReference() {
return maskRef;
package org.apache.fop.pdf;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
import java.util.Collection;
import java.util.List;
+import org.apache.commons.io.output.CountingOutputStream;
+
/**
* Class representing an array object.
*/
/**
* Create a new, empty array object
+ * @param parent the array's parent if any
*/
- public PDFArray() {
+ public PDFArray(PDFObject parent) {
/* generic creation of PDF object */
- super();
+ super(parent);
}
/**
- * Create the array object
- *
+ * Create an array object.
+ * @param parent the array's parent if any
* @param values the actual array wrapped by this object
*/
- public PDFArray(int[] values) {
+ public PDFArray(PDFObject parent, int[] values) {
/* generic creation of PDF object */
- super();
+ super(parent);
for (int i = 0, c = values.length; i < c; i++) {
this.values.add(new Integer(values[i]));
}
/**
- * Create the array object
- *
+ * Create an array object.
+ * @param parent the array's parent if any
* @param values the actual values wrapped by this object
*/
- public PDFArray(Collection values) {
+ public PDFArray(PDFObject parent, Collection values) {
/* generic creation of PDF object */
- super();
+ super(parent);
this.values.addAll(values);
}
/**
* Create the array object
- *
+ * @param parent the array's parent if any
* @param values the actual array wrapped by this object
*/
- public PDFArray(Object[] values) {
+ public PDFArray(PDFObject parent, Object[] values) {
/* generic creation of PDF object */
- super();
+ super(parent);
for (int i = 0, c = values.length; i < c; i++) {
this.values.add(values[i]);
return this.values.get(index);
}
+ /**
+ * Adds a new value to the array.
+ * @param obj the value
+ */
+ public void add(PDFObject obj) {
+ if (obj != null) {
+ obj.setParent(this);
+ }
+ this.values.add(obj);
+ }
+
/**
* Adds a new value to the array.
* @param obj the value
this.values.add(new Double(value));
}
- /**
- * {@inheritDoc}
- */
- public String toPDFString() {
- StringBuffer p = new StringBuffer(64);
+ /** {@inheritDoc} */
+ protected int output(OutputStream stream) throws IOException {
+ CountingOutputStream cout = new CountingOutputStream(stream);
+ Writer writer = PDFDocument.getWriterFor(cout);
if (hasObjectNumber()) {
- p.append(getObjectID());
+ writer.write(getObjectID());
}
- p.append("[");
+
+ writer.write('[');
for (int i = 0; i < values.size(); i++) {
if (i > 0) {
- p.append(" ");
+ writer.write(' ');
}
Object obj = this.values.get(i);
- formatObject(obj, p);
+ formatObject(obj, cout, writer);
}
- p.append("]");
+ writer.write(']');
+
if (hasObjectNumber()) {
- p.append("\nendobj\n");
+ writer.write("\nendobj\n");
}
- return p.toString();
+
+ writer.flush();
+ return cout.getCount();
}
-
+
}
package org.apache.fop.pdf;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+import org.apache.commons.io.output.CountingOutputStream;
+
/**
* class representing a named destination
*/
* @param goToRef Object reference to the GoTo Action
*/
public PDFDestination(String idRef, Object goToRef) {
+ super();
this.goToReference = goToRef;
this.idRef = idRef;
}
- /**
- * Creates the key/value pair for this destination entry for the name tree.
- * @return the formatted key/value pair
- */
- public String toKeyValuePair() {
- StringBuffer sb = new StringBuffer();
- sb.append("(").append(getIDRef()).append(") ");
- if (goToReference instanceof PDFWritable) {
- sb.append(((PDFWritable)goToReference).toInlinePDFString());
- } else {
- sb.append(goToReference);
- }
- return sb.toString();
- }
-
/** {@inheritDoc} */
- protected String toPDFString() {
- return toKeyValuePair();
+ protected int output(OutputStream stream) throws IOException {
+ CountingOutputStream cout = new CountingOutputStream(stream);
+ Writer writer = PDFDocument.getWriterFor(cout);
+
+ formatObject(getIDRef(), cout, writer);
+ writer.write(' ');
+ formatObject(goToReference, cout, writer);
+
+ writer.flush();
+ return cout.getCount();
}
-
+
/**
* Sets the GoToReference in the associated DestinationData object.
*
return false;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public int hashCode() {
return getIDRef().hashCode();
}
*/
public PDFDests(List destinationList) {
this();
- setNames(new PDFArray(destinationList));
+ setNames(new PDFArray(this, destinationList));
}
}
package org.apache.fop.pdf;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import org.apache.commons.io.output.CountingOutputStream;
+
/**
* Class representing a PDF dictionary object
*/
protected List order = new java.util.ArrayList();
/**
- * Create the dictionary object
+ * Create a new dictionary object.
*/
public PDFDictionary() {
- /* generic creation of PDF object */
super();
}
+ /**
+ * Create a new dictionary object.
+ * @param parent the object's parent if any
+ */
+ public PDFDictionary(PDFObject parent) {
+ super(parent);
+ }
+
/**
* Puts a new name/value pair.
* @param name the name
return this.entries.get(name);
}
- /**
- * {@inheritDoc}
- */
- public String toPDFString() {
- StringBuffer p = new StringBuffer(64);
+ /** {@inheritDoc} */
+ protected int output(OutputStream stream) throws IOException {
+ CountingOutputStream cout = new CountingOutputStream(stream);
+ Writer writer = PDFDocument.getWriterFor(cout);
if (hasObjectNumber()) {
- p.append(getObjectID());
+ writer.write(getObjectID());
}
- writeDictionary(p);
+
+ writeDictionary(cout, writer);
+
if (hasObjectNumber()) {
- p.append("endobj\n");
+ writer.write("\nendobj\n");
}
- return p.toString();
+
+ writer.flush();
+ return cout.getCount();
}
-
+
/**
* Writes the contents of the dictionary to a StringBuffer.
- * @param sb the target StringBuffer
+ * @param out the OutputStream (for binary content)
+ * @param writer the Writer (for text content, wraps the above OutputStream)
+ * @throws IOException if an I/O error occurs
*/
- protected void writeDictionary(StringBuffer sb) {
- sb.append("<<");
+ protected void writeDictionary(OutputStream out, Writer writer) throws IOException {
+ writer.write("<<");
boolean compact = (this.order.size() <= 2);
Iterator iter = this.order.iterator();
while (iter.hasNext()) {
String key = (String)iter.next();
if (compact) {
- sb.append(' ');
+ writer.write(' ');
} else {
- sb.append("\n ");
+ writer.write("\n ");
}
- sb.append('/').append(key);
- sb.append(' ');
+ writer.write('/');
+ writer.write(key);
+ writer.write(' ');
Object obj = this.entries.get(key);
- formatObject(obj, sb);
+ formatObject(obj, out, writer);
}
if (compact) {
- sb.append(' ');
+ writer.write(' ');
} else {
- sb.append('\n');
+ writer.write('\n');
}
- sb.append(">>\n");
+ writer.write(">>\n");
}
}
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
+import java.io.Writer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
}
}
+ /**
+ * Creates and returns a Writer object wrapping the given OutputStream. The Writer is
+ * buffered to reduce the number of calls to the encoding converter so don't forget
+ * to <code>flush()</code> the Writer after use or before writing directly to the
+ * underlying OutputStream.
+ * @param out the OutputStream to write to
+ * @return the requested Writer
+ */
+ public static Writer getWriterFor(OutputStream out) {
+ try {
+ return new java.io.BufferedWriter(new java.io.OutputStreamWriter(out, ENCODING));
+ } catch (UnsupportedEncodingException uee) {
+ throw new Error("JVM doesn't support " + ENCODING + " encoding!");
+ }
+ }
+
/**
* set the producer of the document
*
package org.apache.fop.pdf;
// Java
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.IOException;
+import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.security.InvalidKeyException;
+import java.util.Random;
+
+import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
-import javax.crypto.spec.SecretKeySpec;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.BadPaddingException;
import javax.crypto.NoSuchPaddingException;
-
-import java.util.Random;
+import javax.crypto.spec.SecretKeySpec;
/**
* class representing a /Filter /Standard object.
if (this.encryptionKey == null) {
throw new IllegalStateException("PDF Encryption has not been initialized");
}
- log.debug("encrypting with for " + number + " " + generation);
-
byte[] hash = calcHash(number, generation);
return encryptWithHash(data, hash, hash.length);
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public byte[] encrypt(byte[] data, PDFObject refObj) {
- return encryptData(data, refObj.getObjectNumber(), refObj.getGeneration());
+ PDFObject o = refObj;
+ while (o != null && !o.hasObjectNumber()) {
+ o = o.getParent();
+ }
+ if (o == null) {
+ throw new IllegalStateException("No object number could be obtained for a PDF object");
+ }
+ return encryptData(data, o.getObjectNumber(), o.getGeneration());
}
private byte[] calcHash(int number, int generation) {
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.xmp.Metadata;
+
import org.apache.fop.fonts.CIDFont;
import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.FontDescriptor;
import org.apache.fop.fonts.truetype.TTFSubSetFile;
import org.apache.fop.fonts.type1.PFBData;
import org.apache.fop.fonts.type1.PFBParser;
-import org.apache.xmlgraphics.xmp.Metadata;
/**
* This class provides method to create and register PDF objects.
//true for a "deep" structure (one node per entry), true for a "flat" structure
if (deep) {
dests = new PDFDests();
- PDFArray kids = new PDFArray();
+ PDFArray kids = new PDFArray(dests);
Iterator iter = destinationList.iterator();
while (iter.hasNext()) {
PDFDestination dest = (PDFDestination)iter.next();
getDocument().registerObject(node);
node.setLowerLimit(dest.getIDRef());
node.setUpperLimit(dest.getIDRef());
- node.setNames(new PDFArray());
- node.getNames().add(dest);
+ node.setNames(new PDFArray(node));
+ PDFArray names = node.getNames();
+ names.add(dest);
kids.add(node);
}
dests.setLowerLimit(((PDFNameTreeNode)kids.get(0)).getLowerLimit());
* @return the PDF Array with the int values
*/
public PDFArray makeArray(int[] values) {
- PDFArray array = new PDFArray(values);
+ PDFArray array = new PDFArray(null, values);
getDocument().registerObject(array);
return array;
}
private void putFilterEntries(PDFDictionary dict, List names) {
- PDFArray array = new PDFArray();
+ PDFArray array = new PDFArray(dict);
for (int i = 0, c = names.size(); i < c; i++) {
final String name = (String)names.get(i);
if (name.length() > 0) {
private void putDecodeParams(PDFDictionary dict, List parms) {
boolean needParmsEntry = false;
- PDFArray array = new PDFArray();
+ PDFArray array = new PDFArray(dict);
for (int i = 0, c = parms.size(); i < c; i++) {
Object obj = parms.get(i);
if (obj != null) {
public void setBBox(Rectangle2D bbox) {
PDFArray array = (PDFArray)get("BBox");
if (array == null) {
- array = new PDFArray();
+ array = new PDFArray(this);
array.add(bbox.getX());
array.add(bbox.getY());
array.add(bbox.getWidth());
double[] m = new double[6];
at.getMatrix(m);
if (array == null) {
- array = new PDFArray();
+ array = new PDFArray(this);
array.add(m[0]);
array.add(m[1]);
array.add(m[2]);
/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
if (get("Matrix") == null) {
- put("Matrix", new PDFArray(new int[] {1, 0, 0, 1, 0, 0}));
+ put("Matrix", new PDFArray(this, new int[] {1, 0, 0, 1, 0, 0}));
}
put("Resources", resRef);
super.populateStreamDict(lengthEntry);
/**
* Get the PDF reference for a soft mask.
- *
- * @return the PDF reference for a soft mask image
+ * @return the PDF reference for a soft mask image (or null if there's no soft mask)
*/
- String getSoftMask();
-
PDFReference getSoftMaskReference();
/** @return true for CMYK images generated by Adobe Photoshop */
PDFICCStream pdfICCStream = pdfimage.getICCStream();
if (pdfICCStream != null) {
- put("ColorSpace", new PDFArray(new Object[] {new PDFName("ICCBased"), pdfICCStream}));
+ put("ColorSpace", new PDFArray(this,
+ new Object[] {new PDFName("ICCBased"), pdfICCStream}));
} else {
PDFDeviceColorSpace cs = pdfimage.getColorSpace();
put("ColorSpace", new PDFName(cs.getName()));
*/
final Float zero = new Float(0.0f);
final Float one = new Float(1.0f);
- PDFArray decode = new PDFArray();
+ PDFArray decode = new PDFArray(this);
for (int i = 0, c = pdfimage.getColorSpace().getNumComponents(); i < c; i++) {
decode.add(one);
decode.add(zero);
if (pdfimage.isTransparent()) {
PDFColor transp = pdfimage.getTransparentColor();
- PDFArray mask = new PDFArray();
+ PDFArray mask = new PDFArray(this);
mask.add(new Integer(transp.red255()));
mask.add(new Integer(transp.red255()));
mask.add(new Integer(transp.green255()));
package org.apache.fop.pdf;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
/**
* Class representing a PDF name object.
*/
sb.append(DIGITS[ch & 0x0F]);
}
-
/** {@inheritDoc} */
- public String toInlinePDFString() {
+ public String toString() {
return this.name;
}
-
+
/** {@inheritDoc} */
- public String toString() {
- return toInlinePDFString();
+ public void outputInline(OutputStream out, Writer writer) throws IOException {
+ writer.write(toString());
}
}
private PDFArray prepareLimitsArray() {
PDFArray limits = (PDFArray)get(LIMITS);
if (limits == null) {
- limits = new PDFArray(new Object[2]);
+ limits = new PDFArray(this, new Object[2]);
put(LIMITS, limits);
}
if (limits.length() != 2) {
package org.apache.fop.pdf;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
/**
* Class representing a PDF name object.
*/
}
/** {@inheritDoc} */
- public String toInlinePDFString() {
+ public String toString() {
return "null";
}
/** {@inheritDoc} */
- public String toString() {
- return toInlinePDFString();
+ public void outputInline(OutputStream out, Writer writer) throws IOException {
+ writer.write(toString());
}
}
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements. See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/* $Id$ */\r
-\r
-package org.apache.fop.pdf;\r
-\r
-/**\r
- * Class representing a PDF number tree node.\r
- */\r
-public class PDFNumberTreeNode extends PDFDictionary {\r
-\r
- private static final String KIDS = "Kids";\r
- private static final String NUMS = "Nums";\r
- private static final String LIMITS = "Limits";\r
-\r
- /**\r
- * create a named destination\r
- */\r
- public PDFNumberTreeNode() {\r
- /* generic creation of PDF object */\r
- super();\r
- }\r
-\r
- /**\r
- * Sets the Kids array.\r
- * @param kids the Kids array\r
- */\r
- public void setKids(PDFArray kids) {\r
- put(KIDS, kids);\r
- }\r
- \r
- /**\r
- * Returns the Kids array.\r
- * @return the Kids array\r
- */\r
- public PDFArray getKids() {\r
- return (PDFArray)get(KIDS);\r
- }\r
- \r
- /**\r
- * Sets the Nums array.\r
- * @param nums the Nums array\r
- */\r
- public void setNums(PDFNumsArray nums) {\r
- put(NUMS, nums);\r
- }\r
- \r
- /**\r
- * Returns the Nums array.\r
- * @return the Nums array\r
- */\r
- public PDFNumsArray getNums() {\r
- return (PDFNumsArray)get(NUMS);\r
- }\r
- \r
- /**\r
- * Sets the lower limit value of the Limits array.\r
- * @param key the lower limit value\r
- */\r
- public void setLowerLimit(Integer key) {\r
- PDFArray limits = prepareLimitsArray();\r
- limits.set(0, key);\r
- }\r
-\r
- /**\r
- * Returns the lower limit value of the Limits array.\r
- * @return the lower limit value\r
- */\r
- public Integer getLowerLimit() {\r
- PDFArray limits = prepareLimitsArray();\r
- return (Integer)limits.get(0);\r
- }\r
-\r
- /**\r
- * Sets the upper limit value of the Limits array.\r
- * @param key the upper limit value\r
- */\r
- public void setUpperLimit(Integer key) {\r
- PDFArray limits = prepareLimitsArray();\r
- limits.set(1, key);\r
- }\r
-\r
- /**\r
- * Returns the upper limit value of the Limits array.\r
- * @return the upper limit value\r
- */\r
- public Integer getUpperLimit() {\r
- PDFArray limits = prepareLimitsArray();\r
- return (Integer)limits.get(1);\r
- }\r
-\r
-\r
- private PDFArray prepareLimitsArray() {\r
- PDFArray limits = (PDFArray)get(LIMITS);\r
- if (limits == null) {\r
- limits = new PDFArray(new Object[2]);\r
- put(LIMITS, limits);\r
- }\r
- if (limits.length() != 2) {\r
- throw new IllegalStateException("Limits array must have 2 entries");\r
- }\r
- return limits;\r
- }\r
- \r
-}\r
-\r
+/*
+ * 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;
+
+/**
+ * Class representing a PDF number tree node.
+ */
+public class PDFNumberTreeNode extends PDFDictionary {
+
+ private static final String KIDS = "Kids";
+ private static final String NUMS = "Nums";
+ private static final String LIMITS = "Limits";
+
+ /**
+ * create a named destination
+ */
+ public PDFNumberTreeNode() {
+ /* generic creation of PDF object */
+ super();
+ }
+
+ /**
+ * Sets the Kids array.
+ * @param kids the Kids array
+ */
+ public void setKids(PDFArray kids) {
+ put(KIDS, kids);
+ }
+
+ /**
+ * Returns the Kids array.
+ * @return the Kids array
+ */
+ public PDFArray getKids() {
+ return (PDFArray)get(KIDS);
+ }
+
+ /**
+ * Sets the Nums array.
+ * @param nums the Nums array
+ */
+ public void setNums(PDFNumsArray nums) {
+ put(NUMS, nums);
+ }
+
+ /**
+ * Returns the Nums array.
+ * @return the Nums array
+ */
+ public PDFNumsArray getNums() {
+ return (PDFNumsArray)get(NUMS);
+ }
+
+ /**
+ * Sets the lower limit value of the Limits array.
+ * @param key the lower limit value
+ */
+ public void setLowerLimit(Integer key) {
+ PDFArray limits = prepareLimitsArray();
+ limits.set(0, key);
+ }
+
+ /**
+ * Returns the lower limit value of the Limits array.
+ * @return the lower limit value
+ */
+ public Integer getLowerLimit() {
+ PDFArray limits = prepareLimitsArray();
+ return (Integer)limits.get(0);
+ }
+
+ /**
+ * Sets the upper limit value of the Limits array.
+ * @param key the upper limit value
+ */
+ public void setUpperLimit(Integer key) {
+ PDFArray limits = prepareLimitsArray();
+ limits.set(1, key);
+ }
+
+ /**
+ * Returns the upper limit value of the Limits array.
+ * @return the upper limit value
+ */
+ public Integer getUpperLimit() {
+ PDFArray limits = prepareLimitsArray();
+ return (Integer)limits.get(1);
+ }
+
+
+ private PDFArray prepareLimitsArray() {
+ PDFArray limits = (PDFArray)get(LIMITS);
+ if (limits == null) {
+ limits = new PDFArray(this, new Object[2]);
+ put(LIMITS, limits);
+ }
+ if (limits.length() != 2) {
+ throw new IllegalStateException("Limits array must have 2 entries");
+ }
+ return limits;
+ }
+
+}
+
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements. See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/* $Id: PDFArray.java 588547 2007-10-26 07:48:14Z jeremias $ */\r
- \r
-package org.apache.fop.pdf;\r
-\r
-import java.util.Iterator;\r
-import java.util.Map;\r
-import java.util.SortedMap;\r
-\r
-/**\r
- * Class representing an "Nums" array object (for Number Trees).\r
- */\r
-public class PDFNumsArray extends PDFObject {\r
- \r
- /** Sorted Map holding the values of this array. */\r
- protected SortedMap map = new java.util.TreeMap();\r
-\r
- /**\r
- * Create a new, empty array object\r
- */\r
- public PDFNumsArray() {\r
- /* generic creation of PDF object */\r
- super();\r
- }\r
-\r
- /**\r
- * Returns the length of the array\r
- * @return the length of the array\r
- */\r
- public int length() {\r
- return this.map.size();\r
- }\r
- \r
- /**\r
- * Sets an entry.\r
- * @param key the key of the value to set\r
- * @param obj the new value\r
- */\r
- public void put(int key, Object obj) {\r
- this.map.put(new Integer(key), obj);\r
- }\r
- \r
- /**\r
- * Gets an entry.\r
- * @param key the key of requested value\r
- * @return the requested value\r
- */\r
- public Object get(int key) {\r
- return this.map.get(new Integer(key));\r
- }\r
- \r
- /** {@inheritDoc} */\r
- public String toPDFString() {\r
- StringBuffer p = new StringBuffer(64);\r
- if (hasObjectNumber()) {\r
- p.append(getObjectID());\r
- }\r
- p.append("[");\r
- boolean first = true;\r
- Iterator iter = this.map.entrySet().iterator();\r
- while (iter.hasNext()) {\r
- Map.Entry entry = (Map.Entry)iter.next();\r
- if (!first) {\r
- p.append(" ");\r
- }\r
- first = false;\r
- formatObject(entry.getKey(), p);\r
- p.append(" ");\r
- formatObject(entry.getValue(), p);\r
- }\r
- p.append("]");\r
- if (hasObjectNumber()) {\r
- p.append("\nendobj\n");\r
- }\r
- return p.toString();\r
- }\r
-\r
-}\r
+/*
+ * 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;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.SortedMap;
+
+import org.apache.commons.io.output.CountingOutputStream;
+
+/**
+ * Class representing an "Nums" array object (for Number Trees).
+ */
+public class PDFNumsArray extends PDFObject {
+
+ /** Sorted Map holding the values of this array. */
+ protected SortedMap map = new java.util.TreeMap();
+
+ /**
+ * Create a new, empty array object.
+ * @param parent the object's parent if any
+ */
+ public PDFNumsArray(PDFObject parent) {
+ super(parent);
+ }
+
+ /**
+ * Returns the length of the array
+ * @return the length of the array
+ */
+ public int length() {
+ return this.map.size();
+ }
+
+ /**
+ * Sets an entry.
+ * @param key the key of the value to set
+ * @param obj the new value
+ */
+ public void put(int key, Object obj) {
+ this.map.put(new Integer(key), obj);
+ }
+
+ /**
+ * Gets an entry.
+ * @param key the key of requested value
+ * @return the requested value
+ */
+ public Object get(int key) {
+ return this.map.get(new Integer(key));
+ }
+
+ /** {@inheritDoc} */
+ protected int output(OutputStream stream) throws IOException {
+ CountingOutputStream cout = new CountingOutputStream(stream);
+ Writer writer = PDFDocument.getWriterFor(cout);
+ if (hasObjectNumber()) {
+ writer.write(getObjectID());
+ }
+
+ writer.write('[');
+ boolean first = true;
+ Iterator iter = this.map.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry entry = (Map.Entry)iter.next();
+ if (!first) {
+ writer.write(" ");
+ }
+ first = false;
+ formatObject(entry.getKey(), cout, writer);
+ writer.write(" ");
+ formatObject(entry.getValue(), cout, writer);
+ }
+ writer.write(']');
+
+ if (hasObjectNumber()) {
+ writer.write("\nendobj\n");
+ }
+
+ writer.flush();
+ return cout.getCount();
+ }
+
+}
// Java
import java.io.IOException;
import java.io.OutputStream;
+import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
*/
private PDFDocument document;
+ /** the parent PDFObject (may be null and may not always be set, needed for encryption) */
+ private PDFObject parent;
+
/**
* Returns the object's number.
* @return the PDF Object number
return this.objnum;
}
+ /**
+ * Default constructor.
+ */
+ public PDFObject() {
+ //nop
+ }
+
+ /**
+ * Constructor for direct objects.
+ * @param parent the containing PDFObject instance
+ */
+ public PDFObject(PDFObject parent) {
+ setParent(parent);
+ }
+
/**
* Indicates whether this PDFObject has already been assigned an
* object number.
* has not been assigned)
*/
public final PDFDocument getDocument() {
- return this.document;
+ if (this.document != null) {
+ return this.document;
+ } else if (getParent() != null) {
+ return getParent().getDocument();
+ } else {
+ return null;
+ }
}
/**
this.document = doc;
}
+ /**
+ * Returns this objects's parent. The parent is null if it is a "direct object".
+ * @return the parent or null if there's no parent (or it hasn't been set)
+ */
+ public PDFObject getParent() {
+ return this.parent;
+ }
+
+ /**
+ * Sets the direct parent object.
+ * @param parent the direct parent
+ */
+ public void setParent(PDFObject parent) {
+ this.parent = parent;
+ }
+
/**
* Returns the PDF representation of the Object ID.
* @return the Object ID
return pdf.length;
}
+ /** {@inheritDoc} */
+ public void outputInline(OutputStream out, Writer writer) throws IOException {
+ if (hasObjectNumber()) {
+ writer.write(referencePDF());
+ } else {
+ writer.flush();
+ output(out);
+ }
+ }
+
/**
* Encodes the object as a byte array for output to a PDF file.
*
* is normally converted/encoded to a byte array by toPDF(). Only use
* this method to implement the serialization if the object can be fully
* represented as text. If the PDF representation of the object contains
- * binary content use toPDF() or output(OutputStream) instead.
+ * binary content use toPDF() or output(OutputStream) instead. This applies
+ * to any object potentially containing a string object because string object
+ * are encrypted and therefore need to be binary.
* @return String the String representation
*/
protected String toPDFString() {
+ "Use output(OutputStream) instead.");
}
- /**
- * Returns a representation of this object for in-object placement, i.e. if the object
- * has an object number its reference is returned. Otherwise, its PDF representation is
- * returned.
- * @return the String representation
- */
- public String toInlinePDFString() {
- if (hasObjectNumber()) {
- return referencePDF();
- } else {
- return toPDFString();
- }
- }
-
/**
* Converts text to a byte array for writing to a PDF file.
* @param text text to convert/encode
/**
* Formats an object for serialization to PDF.
* @param obj the object
- * @param sb the StringBuffer to write to
+ * @param out the OutputStream to write to
+ * @param writer a Writer for text content (will always be a wrapper around the above
+ * OutputStream. Make sure <code>flush</code> is called when mixing calls)
+ * @throws IOException If an I/O error occurs
*/
- protected void formatObject(Object obj, StringBuffer sb) {
+ protected void formatObject(Object obj, OutputStream out, Writer writer) throws IOException {
if (obj == null) {
- sb.append("null");
+ writer.write("null");
} else if (obj instanceof PDFWritable) {
- sb.append(((PDFWritable)obj).toInlinePDFString());
+ ((PDFWritable)obj).outputInline(out, writer);
} else if (obj instanceof Number) {
if (obj instanceof Double || obj instanceof Float) {
- sb.append(PDFNumber.doubleOut(((Number)obj).doubleValue()));
+ writer.write(PDFNumber.doubleOut(((Number)obj).doubleValue()));
} else {
- sb.append(obj);
+ writer.write(obj.toString());
}
} else if (obj instanceof Boolean) {
- sb.append(obj);
+ writer.write(obj.toString());
} else {
- sb.append("(").append(obj).append(")");
+ writer.flush();
+ out.write(encodeText(obj.toString()));
}
}
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements. See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/* $Id$ */\r
- \r
-package org.apache.fop.pdf;\r
-\r
-/**\r
- * Class representing a PDF /PageLabels dictionary.\r
- */\r
-public class PDFPageLabels extends PDFNumberTreeNode {\r
- \r
- /**\r
- * Create the /PageLabels dictionary\r
- */\r
- public PDFPageLabels() {\r
- super();\r
- }\r
-\r
- /**\r
- * Returns the Nums object\r
- * @return the Nums object (an empty PDFNumsArray for the "/Nums" entry is created\r
- * if it doesn't exist)\r
- */\r
- public PDFNumsArray getNums() {\r
- PDFNumsArray nums = super.getNums();\r
- if (nums == null) {\r
- nums = new PDFNumsArray();\r
- setNums(nums);\r
- }\r
- return nums;\r
- }\r
- \r
-}\r
+/*
+ * 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;
+
+/**
+ * Class representing a PDF /PageLabels dictionary.
+ */
+public class PDFPageLabels extends PDFNumberTreeNode {
+
+ /**
+ * Create the /PageLabels dictionary
+ */
+ public PDFPageLabels() {
+ super();
+ }
+
+ /**
+ * Returns the Nums object
+ * @return the Nums object (an empty PDFNumsArray for the "/Nums" entry is created
+ * if it doesn't exist)
+ */
+ public PDFNumsArray getNums() {
+ PDFNumsArray nums = super.getNums();
+ if (nums == null) {
+ nums = new PDFNumsArray(this);
+ setNums(nums);
+ }
+ return nums;
+ }
+
+}
package org.apache.fop.pdf;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
}
/** {@inheritDoc} */
- public String toInlinePDFString() {
+ public String toString() {
return this.indirectReference;
}
/** {@inheritDoc} */
- public String toString() {
- return toInlinePDFString();
+ public void outputInline(OutputStream out, Writer writer) throws IOException {
+ writer.write(toString());
}
}
if (getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
PDFArray outputIntents = getOutputIntents();
if (outputIntents == null) {
- outputIntents = new PDFArray();
+ outputIntents = new PDFArray(this);
put("OutputIntents", outputIntents);
}
outputIntents.add(outputIntent);
package org.apache.fop.pdf;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
/**
* This interface is implemented by classes that can be serialized to a PDF file either by
* serializing the object or by writing a indirect reference to the actual object.
public interface PDFWritable {
/**
- * Returns a representation of this object for in-object placement, i.e. if the object
- * has an object number its reference is returned. Otherwise, its PDF representation is
- * returned.
- * @return the String representation
+ * Writes a "direct object" (inline object) representation to the stream. A Writer is given
+ * for optimized encoding of text content. Since the Writer is buffered, make sure
+ * <code>flush()</code> is called before any direct calls to <code>out</code> are made.
+ * @param out the OutputStream (for binary content)
+ * @param writer the Writer (for text content, wraps the above OutputStream)
+ * @throws IOException if an I/O error occurs
*/
- String toInlinePDFString();
+ void outputInline(OutputStream out, Writer writer) throws IOException;
}
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.image.EPSImage;
import org.apache.fop.image.FopImage;
import org.apache.fop.image.TIFFImage;
return maskRef;
}
- /** {@inheritDoc} */
- public String getSoftMask() {
- return softMask.toInlinePDFString();
- }
-
/** {@inheritDoc} */
public PDFReference getSoftMaskReference() {
return softMask;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
+import org.w3c.dom.Document;
+
import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.CountingOutputStream;
+
+import org.apache.xmlgraphics.xmp.Metadata;
+import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
+import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
+
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFMetadata;
import org.apache.fop.pdf.PDFNumber;
+import org.apache.fop.pdf.PDFNumsArray;
import org.apache.fop.pdf.PDFOutline;
import org.apache.fop.pdf.PDFOutputIntent;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.render.RendererContext;
import org.apache.fop.util.CharUtilities;
import org.apache.fop.util.ColorProfileUtil;
-import org.apache.xmlgraphics.xmp.Metadata;
-import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
-import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
-import org.w3c.dom.Document;
/**
* Renderer that renders areas to PDF.
this.pdfDoc.getInfo().setTitle(userAgent.getTitle());
this.pdfDoc.getInfo().setKeywords(userAgent.getKeywords());
this.pdfDoc.setFilterMap(filterMap);
- this.pdfDoc.outputHeader(stream);
+ this.pdfDoc.outputHeader(ostream);
//Setup encryption if necessary
PDFEncryptionManager.setupPDFEncryption(encryptionParams, this.pdfDoc);
pageLabels = this.pdfDoc.getFactory().makePageLabels();
this.pdfDoc.getRoot().setPageLabels(pageLabels);
}
- PDFDictionary dict = new PDFDictionary();
+ PDFNumsArray nums = pageLabels.getNums();
+ PDFDictionary dict = new PDFDictionary(nums);
dict.put("P", page.getPageNumberString());
//TODO If the sequence of generated page numbers were inspected, this could be
//expressed in a more space-efficient way
- pageLabels.getNums().put(page.getPageIndex(), dict);
+ nums.put(page.getPageIndex(), dict);
}
/**
<changes>
<release version="FOP Trunk">
+ <action context="Code" dev="JM" type="fix">
+ Fixed generation of named destinations so it works when the PDF document is encrypted.
+ </action>
<action context="Code" dev="JM" type="add">
PostScript output now generates the bounding box DSC comments for the whole document.
</action>