Browse Source

changed pdf streams to use io streams so that they

can be cached
Submitted by:	Paul Reavis <preavis@partnersoft.com>


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194841 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_20_4-doc
Keiron Liddle 22 years ago
parent
commit
812824bfbe

+ 14
- 18
src/org/apache/fop/pdf/ASCII85Filter.java View File

@@ -9,6 +9,7 @@ package org.apache.fop.pdf;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.*;

public class ASCII85Filter extends PDFFilter {
private static final char ASCII85_ZERO = 'z';
@@ -30,9 +31,7 @@ public class ASCII85Filter extends PDFFilter {
return null;
}

public byte[] encode(byte[] data) {

ByteArrayOutputStream buffer = new ByteArrayOutputStream();
public void encode(InputStream in, OutputStream out, int length) throws IOException {

int i;
int total = 0;
@@ -40,16 +39,16 @@ public class ASCII85Filter extends PDFFilter {

// first encode the majority of the data
// each 4 byte group becomes a 5 byte group
for (i = 0; i + 3 < data.length; i += 4) {
for (i = 0; i + 3 < length; i += 4) {

long val = ((data[i] << 24)
long val = ((in.read() << 24)
& 0xff000000L) // note: must have the L at the
+ ((data[i + 1] << 16) & 0xff0000L) // end, otherwise you get into
+ ((data[i + 2] << 8) & 0xff00L) // weird signed value problems
+ (data[i + 3] & 0xffL); // cause we're using a full 32 bits
+ ((in.read() << 16) & 0xff0000L) // end, otherwise you get into
+ ((in.read() << 8) & 0xff00L) // weird signed value problems
+ (in.read() & 0xffL); // cause we're using a full 32 bits
byte[] conv = convertWord(val);

buffer.write(conv, 0, conv.length);
out.write(conv, 0, conv.length);

}

@@ -57,12 +56,12 @@ public class ASCII85Filter extends PDFFilter {
// with n leftover bytes, we append 0 bytes to make a full group of 4
// then convert like normal (except not applying the special zero rule)
// and write out the first n+1 bytes from the result
if (i < data.length) {
int n = data.length - i;
if (i < length) {
int n = length - i;
byte[] lastdata = new byte[4];
for (int j = 0; j < 4; j++) {
if (j < n) {
lastdata[j] = data[i++];
lastdata[j] = (byte)in.read();
} else {
lastdata[j] = 0;
}
@@ -82,18 +81,15 @@ public class ASCII85Filter extends PDFFilter {
}
}
// assert n+1 <= 5
buffer.write(conv, 0, n + 1);
out.write(conv, 0, n + 1);
// System.out.println("ASCII85 end of data was "+n+" bytes long");

}
// finally write the two character end of data marker
buffer.write(ASCII85_EOD.getBytes(), 0,
out.write(ASCII85_EOD.getBytes(), 0,
ASCII85_EOD.getBytes().length);


byte[] result = buffer.toByteArray();


// assert that we have the correct outgoing length
/*
* int in = (data.length % 4);
@@ -103,8 +99,8 @@ public class ASCII85Filter extends PDFFilter {
* System.out.println(" inlength = "+data.length+" inlength % 4 = "+(data.length % 4)+" outlength = "+(result.length-ASCII85_EOD.getBytes().length)+" outlength % 5 = "+((result.length-ASCII85_EOD.getBytes().length) % 5));
* }
*/
return result;

out.close();
}

/**

+ 9
- 11
src/org/apache/fop/pdf/ASCIIHexFilter.java View File

@@ -8,6 +8,7 @@ package org.apache.fop.pdf;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.*;

public class ASCIIHexFilter extends PDFFilter {
private static final String ASCIIHEX_EOD = ">";
@@ -21,19 +22,16 @@ public class ASCIIHexFilter extends PDFFilter {
return null;
}

public byte[] encode(byte[] data) {

StringBuffer buffer = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int val = (int)(data[i] & 0xFF);
public void encode(InputStream in, OutputStream out, int length) throws IOException {
Writer writer = new OutputStreamWriter(out);
for (int i = 0; i < length; i++) {
int val = (int)(in.read() & 0xFF);
if (val < 16)
buffer.append("0");
buffer.append(Integer.toHexString(val));
writer.write("0");
writer.write(Integer.toHexString(val));
}
buffer.append(ASCIIHEX_EOD);

return buffer.toString().getBytes();

writer.write(ASCIIHEX_EOD);
writer.close();
}

}

+ 7
- 3
src/org/apache/fop/pdf/DCTFilter.java View File

@@ -7,9 +7,11 @@

package org.apache.fop.pdf;

import org.apache.fop.util.StreamUtilities;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.*;

/**
* DCT Filter class. Right now it is just used as a dummy filter flag so
@@ -28,8 +30,10 @@ public class DCTFilter extends PDFFilter {
return null;
}

public byte[] encode(byte[] data) {
return data;
public void encode(InputStream in, OutputStream out, int length) throws IOException {
StreamUtilities.streamCopy(in, out, length);
out.close();
}
}


+ 6
- 5
src/org/apache/fop/pdf/FlateFilter.java View File

@@ -7,9 +7,12 @@

package org.apache.fop.pdf;

import org.apache.fop.util.StreamUtilities;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.DeflaterOutputStream;
import java.io.*;

/**
* A filter to deflate a stream. Note that the attributes for
@@ -66,13 +69,12 @@ public class FlateFilter extends PDFFilter {
* because these attributes are not supported. So the DecodeParms
* should be retrieved after calling this method.
*/
public byte[] encode(byte[] data) {
ByteArrayOutputStream outArrayStream = new ByteArrayOutputStream();
public void encode(InputStream in, OutputStream out, int length) throws IOException {
_predictor = PREDICTION_NONE;
try {
DeflaterOutputStream compressedStream =
new DeflaterOutputStream(outArrayStream);
compressedStream.write(data, 0, data.length);
new DeflaterOutputStream(out);
StreamUtilities.streamCopy(in, compressedStream, length);
compressedStream.flush();
compressedStream.close();
} catch (IOException e) {
@@ -80,7 +82,6 @@ public class FlateFilter extends PDFFilter {
// + e.getMessage(), e);
}

return outArrayStream.toByteArray();
}

public void setPredictor(int predictor) throws PDFFilterException {

+ 104
- 0
src/org/apache/fop/pdf/InMemoryStreamCache.java View File

@@ -0,0 +1,104 @@
/*
* $Id$
* Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/

package org.apache.fop.pdf;

import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

/**
* StreamCache implementation that uses temporary files rather than heap.
*/
public class InMemoryStreamCache extends StreamCache {

/**
* The current output stream.
*/
private ByteArrayOutputStream output;

/**
* Creates a new InMemoryStreamCache.
*/
public InMemoryStreamCache() {
}

/**
* Get the current OutputStream. Do not store it - it may change
* from call to call.
*/
public OutputStream getOutputStream() throws IOException {
if (output == null)
output = new ByteArrayOutputStream();
return output;
}

/**
* Filter the cache with the supplied PDFFilter.
*/
public void applyFilter(PDFFilter filter) throws IOException {
if (output == null)
return;

output.close();

// make inputstream from copy of outputted bytes
int size = getSize();
ByteArrayInputStream input =
new ByteArrayInputStream(output.toByteArray());

// reset output
output.reset();

// run filter
filter.encode(input, output, size);
input.close();
output.close();
}

/**
* Outputs the cached bytes to the given stream.
*/
public void outputStreamData(OutputStream stream) throws IOException {
if (output == null)
return;

output.writeTo(stream);
}

/**
* Returns the current size of the stream.
*/
public int getSize() throws IOException {
if (output == null)
return 0;
else
return output.size();
}

/**
* Closes the cache and frees resources.
*/
public void close() throws IOException {
if (output != null) {
output.close();
output = null;
}
}

/**
* Clears and resets the cache.
*/
public void reset() throws IOException {
if (output != null) {
output.close();
output = null;
}
}
}

+ 3
- 3
src/org/apache/fop/pdf/PDFFilter.java View File

@@ -11,6 +11,8 @@

package org.apache.fop.pdf;

import java.io.*;

public abstract class PDFFilter {
/*
* These are no longer needed, but are here as a reminder about what
@@ -60,8 +62,6 @@ public abstract class PDFFilter {
/**
* encode the given data with the filter
*/
public abstract byte[] encode(byte[] data);


public abstract void encode(InputStream in, OutputStream out, int length) throws IOException;

}

+ 1
- 2
src/org/apache/fop/pdf/PDFICCStream.java View File

@@ -11,7 +11,6 @@ import org.apache.fop.datatypes.ColorSpace;
public class PDFICCStream extends PDFStream {
private int origLength;
private int len1, len3;
private byte[] originalData = null;
private ColorSpace cs;
@@ -43,7 +42,7 @@ public class PDFICCStream extends PDFStream {
if (cs.getColorSpace() > 0)
pb.append("/Alternate /").append(cs.getColorSpacePDFString()).append(" ");
pb.append("/Length ").append((_data.size() + 1)).append(" ").append(filterEntry);
pb.append("/Length ").append((_data.getSize() + 1)).append(" ").append(filterEntry);
pb.append(" >>\n");
byte[] p = pb.toString().getBytes();
stream.write(p);

+ 29
- 20
src/org/apache/fop/pdf/PDFStream.java View File

@@ -27,7 +27,7 @@ public class PDFStream extends PDFObject {
/**
* the stream of PDF commands
*/
protected ByteArrayOutputStream _data;
protected StreamCache _data;

/**
* the filters that should be applied
@@ -41,7 +41,11 @@ public class PDFStream extends PDFObject {
*/
public PDFStream(int number) {
super(number);
_data = new ByteArrayOutputStream();
try {
_data = StreamCache.createStreamCache();
} catch (IOException ex) {
ex.printStackTrace();
}
_filters = new ArrayList();
}

@@ -52,7 +56,7 @@ public class PDFStream extends PDFObject {
*/
public void add(String s) {
try {
_data.write(s.getBytes());
_data.getOutputStream().write(s.getBytes());
} catch (IOException ex) {
ex.printStackTrace();
}
@@ -130,21 +134,21 @@ public class PDFStream extends PDFObject {
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
if (r < 16) {
_data.write('0');
_data.getOutputStream().write('0');
}
_data.write(Integer.toHexString(r).getBytes());
_data.getOutputStream().write(Integer.toHexString(r).getBytes());
if (g < 16) {
_data.write('0');
_data.getOutputStream().write('0');
}
_data.write(Integer.toHexString(g).getBytes());
_data.getOutputStream().write(Integer.toHexString(g).getBytes());
if (b < 16) {
_data.write('0');
_data.getOutputStream().write('0');
}
_data.write(Integer.toHexString(b).getBytes());
_data.write(' ');
_data.getOutputStream().write(Integer.toHexString(b).getBytes());
_data.getOutputStream().write(' ');
}
}
_data.write(">\n".getBytes());
_data.getOutputStream().write(">\n".getBytes());
} catch (IOException ex) {
ex.printStackTrace();
}
@@ -153,15 +157,22 @@ public class PDFStream extends PDFObject {

public void setData(byte[] data) throws IOException {
_data.reset();
_data.write(data);
_data.getOutputStream().write(data);
}

/*
public byte[] getData() {
return _data.toByteArray();
}
*/

public int getDataLength() {
return _data.size();
try {
return _data.getSize();
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}


@@ -188,14 +199,13 @@ public class PDFStream extends PDFObject {
throw new RuntimeException();
}


// overload the base object method so we don't have to copy
// byte arrays around so much
protected int output(OutputStream stream) throws IOException {
int length = 0;
String filterEntry = applyFilters();
byte[] p = (this.number + " " + this.generation + " obj\n<< /Length "
+ (_data.size() + 1) + " " + filterEntry
+ (_data.getSize() + 1) + " " + filterEntry
+ " >>\n").getBytes();

stream.write(p);
@@ -216,8 +226,9 @@ public class PDFStream extends PDFObject {
byte[] p = "stream\n".getBytes();
stream.write(p);
length += p.length;
_data.writeTo(stream);
length += _data.size();
_data.outputStreamData(stream);
_data.close();
length += _data.getSize();
p = "\nendstream\n".getBytes();
stream.write(p);
length += p.length;
@@ -243,9 +254,7 @@ public class PDFStream extends PDFObject {
PDFFilter filter = (PDFFilter)_filters.get(count);
// apply the filter encoding if neccessary
if (!filter.isApplied()) {
byte[] tmp = filter.encode(_data.toByteArray());
_data.reset();
_data.write(tmp);
_data.applyFilter(filter);
filter.setApplied(true);
}
// place the names in our local vector in reverse order

+ 2
- 2
src/org/apache/fop/pdf/PDFT1Stream.java View File

@@ -80,7 +80,7 @@ public class PDFT1Stream extends PDFStream {
String filterEntry = applyFilters();
String preData = new String(this.number + " " + this.generation
+ " obj\n<< /Length "
+ (_data.size() + 1) + " " + filterEntry
+ (_data.getSize() + 1) + " " + filterEntry
+ " " + "/Length1 " + len1 + " /Length2 "
+ (origLength - len3 - len1)
+ " /Length3 " + len3 + " >>\n");
@@ -101,7 +101,7 @@ public class PDFT1Stream extends PDFStream {
calcLengths(data);
_data.reset();
// System.out.println("Writing " + size + " bytes of font data");
_data.write(data, 0, size);
_data.getOutputStream().write(data, 0, size);
}

}

+ 2
- 2
src/org/apache/fop/pdf/PDFTTFStream.java View File

@@ -23,7 +23,7 @@ public class PDFTTFStream extends PDFStream {
String filterEntry = applyFilters();
String preData = new String(this.number + " " + this.generation
+ " obj\n<< /Length "
+ (_data.size() + 1) + " " + filterEntry
+ (_data.getSize() + 1) + " " + filterEntry
+ " " + "/Length1 " + origLength
+ " >>\n");

@@ -41,7 +41,7 @@ public class PDFTTFStream extends PDFStream {
public void setData(byte[] data, int size) throws java.io.IOException {
_data.reset();
System.out.println("Writing " + size + " bytes of font data");
_data.write(data, 0, size);
_data.getOutputStream().write(data, 0, size);
}

}

+ 84
- 0
src/org/apache/fop/pdf/StreamCache.java View File

@@ -0,0 +1,84 @@
/*
* $Id$
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/

package org.apache.fop.pdf;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.util.ArrayList;

/**
* class used to store the bytes for a PDFStream. It's actually a generic
* cached byte array, along with a factory that returns either an
* in-memory or tempfile based implementation based on the global
* cacheToFile setting.
*/
public abstract class StreamCache {

/**
* Global setting; controls whether to use tempfiles or not.
*/
private static boolean cacheToFile = false;

/**
* Change the global cacheToFile flag.
*/
public static void setCacheToFile(boolean tizit) {
cacheToFile = tizit;
}

/**
* Get the value of the global cacheToFile flag.
*/
public static boolean getCacheToFile() {
return cacheToFile;
}

/**
* Get the correct implementation (based on cacheToFile) of
* StreamCache.
*/
public static StreamCache createStreamCache() throws IOException {
if (cacheToFile)
return new TempFileStreamCache();
else
return new InMemoryStreamCache();
}

/**
* Get the current OutputStream. Do not store it - it may change
* from call to call.
*/
public abstract OutputStream getOutputStream() throws IOException;

/**
* Filter the cache with the supplied PDFFilter.
*/
public abstract void applyFilter(PDFFilter filter) throws IOException;

/**
* Outputs the cached bytes to the given stream.
*/
public abstract void outputStreamData(OutputStream stream) throws IOException;

/**
* Returns the current size of the stream.
*/
public abstract int getSize() throws IOException;

/**
* Closes the cache and frees resources.
*/
public abstract void close() throws IOException;

/**
* Clears and resets the cache.
*/
public abstract void reset() throws IOException;
}


+ 132
- 0
src/org/apache/fop/pdf/TempFileStreamCache.java View File

@@ -0,0 +1,132 @@
/*
* $Id$
* Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/

package org.apache.fop.pdf;

import org.apache.fop.util.StreamUtilities;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.File;

/**
* StreamCache implementation that uses temporary files rather than heap.
*/
public class TempFileStreamCache extends StreamCache {

/**
* The current output stream.
*/
private BufferedOutputStream output;

/**
* The temp file.
*/
private File tempFile;

/**
* Creates a new TempFileStreamCache.
*/
public TempFileStreamCache() throws IOException {
tempFile = File.createTempFile("org.apache.fop.pdf.StreamCache-",
".temp");
tempFile.deleteOnExit();
}

/**
* Get the current OutputStream. Do not store it - it may change
* from call to call.
*/
public OutputStream getOutputStream() throws IOException {
if (output == null)
output = new BufferedOutputStream(
new FileOutputStream(tempFile));
return output;
}

/**
* Filter the cache with the supplied PDFFilter.
*/
public void applyFilter(PDFFilter filter) throws IOException {
if (output == null)
return;

output.close();
output = null;

// need a place to put results
File newTempFile =
File.createTempFile("org.apache.fop.pdf.StreamCache-",
".temp");
newTempFile.deleteOnExit();

// filter may not be buffered
BufferedInputStream input =
new BufferedInputStream(new FileInputStream(tempFile));
BufferedOutputStream output = new BufferedOutputStream(
new FileOutputStream(newTempFile));
filter.encode(input, output, (int) tempFile.length());
input.close();
output.close();
tempFile.delete();
tempFile = newTempFile;
}

/**
* Outputs the cached bytes to the given stream.
*/
public void outputStreamData(OutputStream stream) throws IOException {
if (output == null)
return;

output.close();
output = null;

// don't need a buffer because streamCopy is buffered
FileInputStream input = new FileInputStream(tempFile);
StreamUtilities.streamCopy(input, output);
input.close();
}

/**
* Returns the current size of the stream.
*/
public int getSize() throws IOException {
if (output != null)
output.flush();
return (int) tempFile.length();
}

/**
* Closes the cache and frees resources.
*/
public void close() throws IOException {
if (output != null) {
output.close();
output = null;
}
if (tempFile.exists())
tempFile.delete();
}

/**
* Clears and resets the cache.
*/
public void reset() throws IOException {
if (output != null) {
output.close();
output = null;
}
if (tempFile.exists())
tempFile.delete();
}
}

+ 3
- 2
src/org/apache/fop/tools/AreaTreeBuilder.java View File

@@ -117,7 +117,7 @@ public class AreaTreeBuilder {
PageViewport page = sm.getPage(count, c);
c++;
// save the page to a stream for testing
ObjectOutputStream tempstream = new ObjectOutputStream(
/*ObjectOutputStream tempstream = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream("temp.ser")));
page.savePage(tempstream);
@@ -129,7 +129,7 @@ public class AreaTreeBuilder {
new BufferedInputStream(
new FileInputStream("temp.ser")));
page.loadPage(in);
in.close();
in.close();*/

rend.renderPage(page);
}
@@ -331,6 +331,7 @@ class TreeLoader {
reg.addBlock(obj);
}
}
reg.setCTM(new CTM());
return reg;
}


+ 147
- 0
src/org/apache/fop/util/StreamUtilities.java View File

@@ -0,0 +1,147 @@
/*
* $Id$
* Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/
package org.apache.fop.util;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.EOFException;
import java.io.DataInput;
import java.io.DataOutput;
import java.util.zip.CRC32;

/**
* General handy stream i/o methods.
*/
public class StreamUtilities {

/**
* Size of buffers. Duh.
*/
public static final int BUFFER_SIZE = 4096; // cuz I like big buffers...

/**
* Binary copies bytes from an input stream to an output stream.
* The process is buffered, so you shouldn't need
* BufferedInput/OutputStreams. Flushes when it's finished, but does
* not close either stream. Returns the number of bytes copied.
*/
public static long streamCopy(InputStream source,
OutputStream sink) throws IOException {
// set table
byte[] buffer = new byte[BUFFER_SIZE];
long total = 0;

// trough
int scoop;
while ((scoop = source.read(buffer)) >= 0) {
if (scoop == 0)
System.out.println("zero scoop!");
sink.write(buffer, 0, scoop);
total += scoop;
}

// do dishes
sink.flush();

return total;
}

/**
* Binary copies up to the given number of bytes from an input
* stream to an output stream. The process is buffered, so you
* shouldn't need BufferedInput/OutputStreams.
* Flushes when it's finished, but does not close either stream.
* Throws an EOFExeption if there aren't enough bytes available to
* transfer the requested amount.
* Returns the total number of bytes copied.
*/
public static long streamCopy(InputStream source,
OutputStream sink, int howMany) throws IOException {
// set table
byte[] buffer = new byte[BUFFER_SIZE];
int left = howMany;

// trough
int scoop;
while (left > 0) {
scoop = source.read(buffer, 0, Math.min(BUFFER_SIZE, left));
if (scoop < 0)
throw new EOFException(
"Not enough bytes to feed you in IOLib.streamCopy(source, sink, howMany); you asked for " +
howMany + " and I only have " + (howMany - left));

sink.write(buffer, 0, scoop);
left -= scoop;
}

// do dishes
sink.flush();

return howMany;
}

/**
* Binary copies up to the given number of bytes from an input
* stream to an output stream. The process is buffered, so you
* shouldn't need BufferedInput/OutputStreams.
* Flushes when it's finished, but does not close either stream.
* Throws an EOFExeption if there aren't enough bytes available
* to transfer the requested amount.
* Returns the checksum of the bytes copied.
*/
public static long streamCopyWithChecksum(InputStream source,
OutputStream sink, int howMany) throws IOException {
// set table
byte[] buffer = new byte[BUFFER_SIZE];
int left = howMany;
CRC32 checksummer = new CRC32();

// trough
int scoop;
while (left > 0) {
scoop = source.read(buffer, 0, Math.min(BUFFER_SIZE, left));
if (scoop < 0)
throw new EOFException("Not enough bytes to feed you in IOLib.streamCopy(source, sink, howMany)");

checksummer.update(buffer, 0, scoop);
sink.write(buffer, 0, scoop);
left -= scoop;
}

// do dishes
sink.flush();

return checksummer.getValue();
}

/**
* Binary copies up to the given number of bytes from a DataInput
* object to an DataOutput object. The process is buffered. Since
* DataOutput doesn't support closing or flushing, it does neither.
* Returns the total number of bytes copied.
*/
public static long dataCopy(DataInput source, DataOutput sink,
int howMany) throws IOException {
// set table
byte[] buffer = new byte[BUFFER_SIZE];
int left = howMany;

// trough
int scoop;
while (left > 0) {
scoop = Math.min(BUFFER_SIZE, left);
source.readFully(buffer, 0, scoop);
sink.write(buffer, 0, scoop);
left -= scoop;
}

// do dishes
return howMany;
}

}

Loading…
Cancel
Save