I had to refactor the PDF library a little bit but since it only affects the inner API it shouldn't be a problem that I removed some methods which caused trouble because a didn't think about encryption when I worked on the PDF library last year. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@611114 13f79535-47bb-0310-9956-ffa450edef68tags/fop-0_95beta
@@ -21,8 +21,10 @@ package org.apache.fop.pdf; | |||
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; | |||
/** | |||
@@ -169,8 +171,12 @@ public abstract class AbstractPDFStream extends PDFDictionary { | |||
* {@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; | |||
@@ -184,38 +190,21 @@ public abstract class AbstractPDFStream extends PDFDictionary { | |||
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(); | |||
} | |||
/** |
@@ -163,15 +163,6 @@ public class BitmapImage implements PDFImage { | |||
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; |
@@ -19,9 +19,14 @@ | |||
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. | |||
*/ | |||
@@ -33,20 +38,21 @@ public class PDFArray extends PDFObject { | |||
/** | |||
* 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])); | |||
@@ -54,25 +60,25 @@ public class PDFArray extends PDFObject { | |||
} | |||
/** | |||
* 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]); | |||
@@ -114,6 +120,17 @@ public class PDFArray extends PDFObject { | |||
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 | |||
@@ -130,27 +147,30 @@ public class PDFArray extends PDFObject { | |||
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(); | |||
} | |||
} |
@@ -19,6 +19,12 @@ | |||
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 | |||
*/ | |||
@@ -40,30 +46,24 @@ public class PDFDestination extends PDFObject { | |||
* @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. | |||
* | |||
@@ -124,9 +124,7 @@ public class PDFDestination extends PDFObject { | |||
return false; | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public int hashCode() { | |||
return getIDRef().hashCode(); | |||
} |
@@ -40,7 +40,7 @@ public class PDFDests extends PDFNameTreeNode { | |||
*/ | |||
public PDFDests(List destinationList) { | |||
this(); | |||
setNames(new PDFArray(destinationList)); | |||
setNames(new PDFArray(this, destinationList)); | |||
} | |||
} |
@@ -19,10 +19,15 @@ | |||
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 | |||
*/ | |||
@@ -40,13 +45,20 @@ public class PDFDictionary extends PDFObject { | |||
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 | |||
@@ -80,47 +92,53 @@ public class PDFDictionary extends PDFObject { | |||
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"); | |||
} | |||
} |
@@ -24,15 +24,16 @@ import java.io.IOException; | |||
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; | |||
@@ -316,6 +317,22 @@ public class PDFDocument { | |||
} | |||
} | |||
/** | |||
* 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 | |||
* |
@@ -20,20 +20,20 @@ | |||
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. | |||
@@ -358,17 +358,20 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption { | |||
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) { |
@@ -39,6 +39,9 @@ import org.apache.commons.io.IOUtils; | |||
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; | |||
@@ -51,7 +54,6 @@ import org.apache.fop.fonts.truetype.FontFileReader; | |||
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. | |||
@@ -872,7 +874,7 @@ public class PDFFactory { | |||
//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(); | |||
@@ -880,8 +882,9 @@ public class PDFFactory { | |||
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()); | |||
@@ -1527,7 +1530,7 @@ public class PDFFactory { | |||
* @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; |
@@ -277,7 +277,7 @@ public class PDFFilterList { | |||
} | |||
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) { | |||
@@ -323,7 +323,7 @@ public class PDFFilterList { | |||
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) { |
@@ -63,7 +63,7 @@ public class PDFFormXObject extends PDFXObject { | |||
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()); | |||
@@ -105,7 +105,7 @@ public class PDFFormXObject extends PDFXObject { | |||
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]); | |||
@@ -170,7 +170,7 @@ public class PDFFormXObject extends PDFXObject { | |||
/** {@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); |
@@ -105,11 +105,8 @@ public interface PDFImage { | |||
/** | |||
* 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 */ |
@@ -94,7 +94,8 @@ public class PDFImageXObject extends PDFXObject { | |||
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())); | |||
@@ -107,7 +108,7 @@ public class PDFImageXObject extends PDFXObject { | |||
*/ | |||
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); | |||
@@ -117,7 +118,7 @@ public class PDFImageXObject extends PDFXObject { | |||
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())); |
@@ -19,6 +19,10 @@ | |||
package org.apache.fop.pdf; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.io.Writer; | |||
/** | |||
* Class representing a PDF name object. | |||
*/ | |||
@@ -65,15 +69,14 @@ public class PDFName implements PDFWritable { | |||
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()); | |||
} | |||
} |
@@ -108,7 +108,7 @@ public class PDFNameTreeNode extends PDFDictionary { | |||
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) { |
@@ -19,6 +19,10 @@ | |||
package org.apache.fop.pdf; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.io.Writer; | |||
/** | |||
* Class representing a PDF name object. | |||
*/ | |||
@@ -35,13 +39,13 @@ public final class PDFNull implements PDFWritable { | |||
} | |||
/** {@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()); | |||
} | |||
} |
@@ -1,121 +1,121 @@ | |||
/* | |||
* 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(new Object[2]); | |||
put(LIMITS, limits); | |||
} | |||
if (limits.length() != 2) { | |||
throw new IllegalStateException("Limits array must have 2 entries"); | |||
} | |||
return limits; | |||
} | |||
} | |||
/* | |||
* 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; | |||
} | |||
} | |||
@@ -1,94 +1,104 @@ | |||
/* | |||
* 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: PDFArray.java 588547 2007-10-26 07:48:14Z jeremias $ */ | |||
package org.apache.fop.pdf; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
import java.util.SortedMap; | |||
/** | |||
* 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 | |||
*/ | |||
public PDFNumsArray() { | |||
/* generic creation of PDF object */ | |||
super(); | |||
} | |||
/** | |||
* 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} */ | |||
public String toPDFString() { | |||
StringBuffer p = new StringBuffer(64); | |||
if (hasObjectNumber()) { | |||
p.append(getObjectID()); | |||
} | |||
p.append("["); | |||
boolean first = true; | |||
Iterator iter = this.map.entrySet().iterator(); | |||
while (iter.hasNext()) { | |||
Map.Entry entry = (Map.Entry)iter.next(); | |||
if (!first) { | |||
p.append(" "); | |||
} | |||
first = false; | |||
formatObject(entry.getKey(), p); | |||
p.append(" "); | |||
formatObject(entry.getValue(), p); | |||
} | |||
p.append("]"); | |||
if (hasObjectNumber()) { | |||
p.append("\nendobj\n"); | |||
} | |||
return p.toString(); | |||
} | |||
} | |||
/* | |||
* 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(); | |||
} | |||
} |
@@ -22,6 +22,7 @@ package org.apache.fop.pdf; | |||
// 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; | |||
@@ -57,6 +58,9 @@ public abstract class PDFObject implements PDFWritable { | |||
*/ | |||
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 | |||
@@ -68,6 +72,21 @@ public abstract class PDFObject implements PDFWritable { | |||
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. | |||
@@ -102,7 +121,13 @@ public abstract class PDFObject implements PDFWritable { | |||
* 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; | |||
} | |||
} | |||
/** | |||
@@ -127,6 +152,22 @@ public abstract class PDFObject implements PDFWritable { | |||
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 | |||
@@ -169,6 +210,16 @@ public abstract class PDFObject implements PDFWritable { | |||
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. | |||
* | |||
@@ -184,7 +235,9 @@ public abstract class PDFObject implements PDFWritable { | |||
* 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() { | |||
@@ -192,20 +245,6 @@ public abstract class PDFObject implements PDFWritable { | |||
+ "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 | |||
@@ -250,23 +289,27 @@ public abstract class PDFObject implements PDFWritable { | |||
/** | |||
* 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())); | |||
} | |||
} | |||
@@ -1,48 +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; | |||
/** | |||
* 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(); | |||
setNums(nums); | |||
} | |||
return nums; | |||
} | |||
} | |||
/* | |||
* 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; | |||
} | |||
} |
@@ -19,6 +19,9 @@ | |||
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; | |||
@@ -68,13 +71,13 @@ public class PDFReference implements PDFWritable { | |||
} | |||
/** {@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()); | |||
} | |||
} |
@@ -225,7 +225,7 @@ public class PDFRoot extends PDFDictionary { | |||
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); |
@@ -19,6 +19,10 @@ | |||
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. | |||
@@ -26,11 +30,13 @@ package org.apache.fop.pdf; | |||
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; | |||
} |
@@ -25,6 +25,7 @@ import java.io.OutputStream; | |||
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; | |||
@@ -237,11 +238,6 @@ public class FopPDFImage implements PDFImage { | |||
return maskRef; | |||
} | |||
/** {@inheritDoc} */ | |||
public String getSoftMask() { | |||
return softMask.toInlinePDFString(); | |||
} | |||
/** {@inheritDoc} */ | |||
public PDFReference getSoftMaskReference() { | |||
return softMask; |
@@ -37,7 +37,15 @@ import java.util.Map; | |||
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; | |||
@@ -86,6 +94,7 @@ import org.apache.fop.pdf.PDFInfo; | |||
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; | |||
@@ -102,10 +111,6 @@ import org.apache.fop.render.Graphics2DAdapter; | |||
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. | |||
@@ -357,7 +362,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { | |||
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); | |||
@@ -725,11 +730,12 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { | |||
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); | |||
} | |||
/** |
@@ -28,6 +28,9 @@ | |||
<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> |