gnujpdf reformat

This commit is contained in:
Jindra Petřík
2021-02-20 10:01:49 +01:00
parent 7eb151055b
commit df913281dc
24 changed files with 3587 additions and 3574 deletions

View File

@@ -25,194 +25,198 @@ import java.io.*;
import java.util.*;
/**
* This class is used to write a PDF document. It acts as a wrapper
* to a real OutputStream, but is necessary for certain internal PDF
* structures to be built correctly.
* This class is used to write a PDF document. It acts as a wrapper to a real
* OutputStream, but is necessary for certain internal PDF structures to be
* built correctly.
*
* @author Peter T. Mount
* @author Eric Z. Beard, ericzbeard@hotmail.com
* @version $Revision: 1.3 $, $Date: 2007/09/22 12:48:16 $
*/
public class PDFOutput
{
/**
* This is the actual OutputStream used to write to.
*/
protected OutputStream os;
/**
* This is the OutputStream used to write each object to.
*
* <p>We use a separate stream, because we need to keep track of how
* many bytes have been written for each object for the xref table to
* work correctly.
*/
protected ByteArrayOutputStream baos;
/**
* This is the current position within the stream
*/
protected int offset;
/**
* This vector contains offsets of each object
*/
protected Vector<PDFXref> offsets;
/**
* This is used to track the /Root object (catalog)
*/
protected PDFObject rootID;
/**
* This is used to track the /Info object (info)
*/
protected PDFObject infoID;
/**
* This creates a PDF OutputStream
*
* @param os The output stream to write the PDF file to.
* @throws IOException if there is an I/O error.
*/
public PDFOutput(OutputStream os) throws IOException
{
this.os = os;
offset = 0;
offsets = new Vector<PDFXref>();
baos = new ByteArrayOutputStream();
// Now write the PDF header
//
// Note: As the encoding is fixed here, we use getBytes().
//
baos.write("%PDF-1.2\n".getBytes());
// This second comment is advised in the PDF Reference manual
// page 61
baos.write("%\342\343\317\323\n".getBytes());
offset = baos.size();
baos.writeTo(os);
}
/**
* This method writes a PDFObject to the stream.
*
* @param ob PDFObject Obeject to write
* @exception IOException on error
*/
protected void write(PDFObject ob) throws IOException
{
// Check the object to see if it's one that is needed in the trailer
// object
if(ob instanceof PDFCatalog) rootID=ob;
if(ob instanceof PDFInfo) infoID=ob;
offsets.addElement(new PDFXref(ob.getSerialID(),offset));
baos.reset();
ob.write(baos);
offset+=baos.size();
baos.writeTo(os);
}
/**
* This closes the Stream, writing the xref table
*/
protected void close() throws IOException
{
// Make sure everything is written
os.flush();
// we use baos to speed things up a little.
// Also, offset is preserved, and marks the begining of this block.
// This is required by PDF at the end of the PDF file.
baos.reset();
baos.write("xref\n".getBytes());
// Now a single subsection for object 0
//baos.write("0 1\n0000000000 65535 f \n".getBytes());
// Now scan through the offsets list. The should be in sequence,
// but just in case:
int firstid = 0; // First id in block
int lastid = -1; // The last id used
Vector<PDFXref> block = new Vector<PDFXref>(); // xrefs in this block
// We need block 0 to exist
block.addElement(new PDFXref(0,0,65535));
for(PDFXref x : offsets) {
if(firstid==-1) firstid=x.id;
// check to see if block is in range (-1 means empty)
if(lastid>-1 && x.id != (lastid+1)) {
// no, so write this block, and reset
writeblock(firstid,block);
block.removeAllElements();
firstid=-1;
}
// now add to block
block.addElement(x);
lastid = x.id;
public class PDFOutput {
/**
* This is the actual OutputStream used to write to.
*/
protected OutputStream os;
/**
* This is the OutputStream used to write each object to.
*
* <p>
* We use a separate stream, because we need to keep track of how many bytes
* have been written for each object for the xref table to work correctly.
*/
protected ByteArrayOutputStream baos;
/**
* This is the current position within the stream
*/
protected int offset;
/**
* This vector contains offsets of each object
*/
protected Vector<PDFXref> offsets;
/**
* This is used to track the /Root object (catalog)
*/
protected PDFObject rootID;
/**
* This is used to track the /Info object (info)
*/
protected PDFObject infoID;
/**
* This creates a PDF OutputStream
*
* @param os The output stream to write the PDF file to.
* @throws IOException if there is an I/O error.
*/
public PDFOutput(OutputStream os) throws IOException {
this.os = os;
offset = 0;
offsets = new Vector<PDFXref>();
baos = new ByteArrayOutputStream();
// Now write the PDF header
//
// Note: As the encoding is fixed here, we use getBytes().
//
baos.write("%PDF-1.2\n".getBytes());
// This second comment is advised in the PDF Reference manual
// page 61
baos.write("%\342\343\317\323\n".getBytes());
offset = baos.size();
baos.writeTo(os);
}
// now write the last block
if(firstid>-1)
writeblock(firstid,block);
// now the trailer object
baos.write("trailer\n<<\n".getBytes());
// the number of entries (REQUIRED)
baos.write("/Size ".getBytes());
baos.write(Integer.toString(offsets.size()+1).getBytes());
baos.write("\n".getBytes());
// the /Root catalog indirect reference (REQUIRED)
if(rootID != null) {
baos.write("/Root ".getBytes());
baos.write(rootID.toString().getBytes());
baos.write("\n".getBytes());
} else
throw new IOException("Root object is not present in document");
// the /Info reference (OPTIONAL)
if(infoID != null) {
baos.write("/Info ".getBytes());
baos.write(infoID.toString().getBytes());
baos.write("\n".getBytes());
/**
* This method writes a PDFObject to the stream.
*
* @param ob PDFObject Obeject to write
* @exception IOException on error
*/
protected void write(PDFObject ob) throws IOException {
// Check the object to see if it's one that is needed in the trailer
// object
if (ob instanceof PDFCatalog) {
rootID = ob;
}
if (ob instanceof PDFInfo) {
infoID = ob;
}
offsets.addElement(new PDFXref(ob.getSerialID(), offset));
baos.reset();
ob.write(baos);
offset += baos.size();
baos.writeTo(os);
}
// end the trailer object
baos.write(">>\nstartxref\n".getBytes());
baos.write(Integer.toString(offset).getBytes());
baos.write("\n%%EOF\n".getBytes());
// now flush the stream
baos.writeTo(os);
os.flush();
}
/**
* Writes a block of references to the PDF file
* @param firstid ID of the first reference in this block
* @param block Vector containing the references in this block
* @exception IOException on write error
*/
protected void writeblock(int firstid,Vector<PDFXref> block) throws IOException
{
baos.write(Integer.toString(firstid).getBytes());
baos.write(" ".getBytes());
baos.write(Integer.toString(block.size()).getBytes());
baos.write("\n".getBytes());
//baos.write("\n0000000000 65535 f\n".getBytes());
for(PDFXref x : block) {
baos.write(x.toString().getBytes());
baos.write("\n".getBytes());
/**
* This closes the Stream, writing the xref table
*/
protected void close() throws IOException {
// Make sure everything is written
os.flush();
// we use baos to speed things up a little.
// Also, offset is preserved, and marks the begining of this block.
// This is required by PDF at the end of the PDF file.
baos.reset();
baos.write("xref\n".getBytes());
// Now a single subsection for object 0
//baos.write("0 1\n0000000000 65535 f \n".getBytes());
// Now scan through the offsets list. The should be in sequence,
// but just in case:
int firstid = 0; // First id in block
int lastid = -1; // The last id used
Vector<PDFXref> block = new Vector<PDFXref>(); // xrefs in this block
// We need block 0 to exist
block.addElement(new PDFXref(0, 0, 65535));
for (PDFXref x : offsets) {
if (firstid == -1) {
firstid = x.id;
}
// check to see if block is in range (-1 means empty)
if (lastid > -1 && x.id != (lastid + 1)) {
// no, so write this block, and reset
writeblock(firstid, block);
block.removeAllElements();
firstid = -1;
}
// now add to block
block.addElement(x);
lastid = x.id;
}
// now write the last block
if (firstid > -1) {
writeblock(firstid, block);
}
// now the trailer object
baos.write("trailer\n<<\n".getBytes());
// the number of entries (REQUIRED)
baos.write("/Size ".getBytes());
baos.write(Integer.toString(offsets.size() + 1).getBytes());
baos.write("\n".getBytes());
// the /Root catalog indirect reference (REQUIRED)
if (rootID != null) {
baos.write("/Root ".getBytes());
baos.write(rootID.toString().getBytes());
baos.write("\n".getBytes());
} else {
throw new IOException("Root object is not present in document");
}
// the /Info reference (OPTIONAL)
if (infoID != null) {
baos.write("/Info ".getBytes());
baos.write(infoID.toString().getBytes());
baos.write("\n".getBytes());
}
// end the trailer object
baos.write(">>\nstartxref\n".getBytes());
baos.write(Integer.toString(offset).getBytes());
baos.write("\n%%EOF\n".getBytes());
// now flush the stream
baos.writeTo(os);
os.flush();
}
/**
* Writes a block of references to the PDF file
*
* @param firstid ID of the first reference in this block
* @param block Vector containing the references in this block
* @exception IOException on write error
*/
protected void writeblock(int firstid, Vector<PDFXref> block) throws IOException {
baos.write(Integer.toString(firstid).getBytes());
baos.write(" ".getBytes());
baos.write(Integer.toString(block.size()).getBytes());
baos.write("\n".getBytes());
//baos.write("\n0000000000 65535 f\n".getBytes());
for (PDFXref x : block) {
baos.write(x.toString().getBytes());
baos.write("\n".getBytes());
}
}
}
} // end class PDFOutput