[FOray-commit] SF.net SVN: foray:[12511] trunk/foray/foray-pdf/src
Modular XSL-FO Implementation for Java.
Status: Alpha
Brought to you by:
victormote
|
From: <vic...@us...> - 2022-01-30 17:02:38
|
Revision: 12511
http://sourceforge.net/p/foray/code/12511
Author: victormote
Date: 2022-01-30 17:02:34 +0000 (Sun, 30 Jan 2022)
Log Message:
-----------
Move remaining serialization code from PdfDocument4a to PdfSerializer.
Modified Paths:
--------------
trunk/foray/foray-pdf/src/main/java/org/foray/pdf/document/PdfDocument4a.java
trunk/foray/foray-pdf/src/main/java/org/foray/pdf/encrypt/PdfEncryption4a.java
trunk/foray/foray-pdf/src/main/java/org/foray/pdf/serial/PdfSerializer.java
trunk/foray/foray-pdf/src/main/java/org/foray/pdf/serial/PdfTrailer.java
trunk/foray/foray-pdf/src/test/java/org/foray/pdf/object/PdfDocumentTests.java
Modified: trunk/foray/foray-pdf/src/main/java/org/foray/pdf/document/PdfDocument4a.java
===================================================================
--- trunk/foray/foray-pdf/src/main/java/org/foray/pdf/document/PdfDocument4a.java 2022-01-30 15:28:52 UTC (rev 12510)
+++ trunk/foray/foray-pdf/src/main/java/org/foray/pdf/document/PdfDocument4a.java 2022-01-30 17:02:34 UTC (rev 12511)
@@ -37,7 +37,8 @@
package org.foray.pdf.document;
import org.foray.common.ColorUtil;
-import org.foray.common.sequence.ByteArrayBuilder;
+import org.foray.common.primitive.ObjectUtils;
+import org.foray.common.sequence.ByteArray;
import org.foray.common.sequence.IntArrayBuilder;
import org.foray.pdf.PdfConstants;
import org.foray.pdf.PdfObjectReference;
@@ -52,13 +53,13 @@
import org.foray.pdf.interact.PdfPageLabel;
import org.foray.pdf.interact.annotation.PdfBorderStyle;
import org.foray.pdf.interchange.PdfDocumentInfo4a;
-import org.foray.pdf.serial.PdfCrossRefEntry;
-import org.foray.pdf.serial.PdfCrossRefInfo;
import org.foray.pdf.serial.PdfParser;
import org.foray.pdf.serial.PdfSerializer;
import org.foray.pdf.serial.PdfTrailer;
import org.foray.pdf.text.PdfEncoding4a;
import org.foray.pdf.text.PdfFont4a;
+import org.foray.pdf.type.PdfArray;
+import org.foray.pdf.type.PdfHexString;
import org.foray.pdf.type.PdfObject;
import org.axsl.font.Font;
@@ -97,6 +98,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Random;
/**
* Represents a PDF document.
@@ -117,9 +119,12 @@
* bytes. */
public static final String ENCODING = "ISO-8859-1";
- /** The current character position. */
- private long position = 0;
+ /** This document's permanent file ID, if any. */
+ private ByteArray permanentFileId;
+ /** This document's incremental file ID, if any. */
+ private ByteArray incrementalFileId;
+
/** The list of indirectly-referenced objects in this document. The index into the list is the object's object
* number, and should match the object number in {@link PdfObject#getIndirectReference()}. */
private List<PdfObject> indirectObjects = new ArrayList<PdfObject>();
@@ -204,10 +209,6 @@
/** The PostScript server. */
private PsServer psServer;
- /** The trailer dictionary. Always use {@link #getTrailer()} to obtain the instance, because it is lazily
- * created. */
- private PdfTrailer lazyTrailer;
-
/**
* Constructor which creates an empty PDF document.
* The constructor creates a /Root and /Pages object to track the document
@@ -237,7 +238,9 @@
*/
public PdfDocument4a(final PdfParser parser) throws PdfException {
final PdfVersion pdfVersion = parser.parseHeader();
- this.lazyTrailer = parser.parseTrailer();
+ final PdfTrailer trailer = parser.parseTrailer();
+ /* TODO: Figure out what we need from the trailer during parsing. */
+ ObjectUtils.noOperation(trailer);
parser.parseIndirectObjects();
setVersion(pdfVersion);
}
@@ -291,60 +294,8 @@
return this.resources;
}
- private PdfCrossRefInfo writeIndirectObjects(final OutputStream output) throws PdfException {
- final PdfCrossRefInfo xrefInfo = new PdfCrossRefInfo();
-
- /*
- * Use a "while" loop here, because as each object is written, it has
- * potential to reference another object indirectly, which will add an
- * item to indirectObjects.
- */
- int objectId = 1;
- while (objectId < this.indirectObjects.size()) {
- final PdfObject object = this.indirectObjects.get(objectId);
- if (object != null) {
- final PdfObjectReference reference = object.getIndirectReference();
- if (this.indirectWriteLast.contains(reference.getNumber())) {
- /* We are not serializing this object yet. */
- } else {
- /* Output the object and increment the character position by the object's length. */
- final PdfCrossRefEntry xref = new PdfCrossRefEntry(object);
- xref.setOffset(this.position);
- xrefInfo.setTableEntry(reference.getNumber(), xref);
- this.position += object.serialize(output, this);
- }
- }
- objectId ++;
- }
- return xrefInfo;
- }
-
- private void writeDeferredIndirectObjects(final OutputStream output, final PdfCrossRefInfo xrefInfo)
- throws PdfException {
- /* Treat the deferred items like a stack, and iterate in reverse order. */
- final IntPrimitiveIterator deferredObjectIterator = this.indirectWriteLast.iteratorReverse();
- while (deferredObjectIterator.hasNext()) {
- final int objectId = deferredObjectIterator.nextInt();
- final PdfObject object = this.indirectObjects.get(objectId);
- if (object != null) {
- final PdfObjectReference reference = object.getIndirectReference();
- final PdfCrossRefEntry xref = new PdfCrossRefEntry(object);
- xref.setOffset(this.position);
- xrefInfo.setTableEntry(reference.getNumber(), xref);
- this.position += object.serialize(output, this);
- }
- }
- }
-
- /**
- * Write the document trailer.
- * @param output The output stream.
- * @param xrefPosition The offset to the cross-reference table.
- * @throws PdfException For errors while writing to the output stream.
- */
- private void writeTrailer(final OutputStream output, final long xrefPosition) throws PdfException, IOException {
- /* Construct the trailer. */
- final PdfTrailer trailer = getTrailer();
+ public PdfTrailer getTrailer() {
+ final PdfTrailer trailer = new PdfTrailer();
trailer.put("Size", this.indirectObjects.size());
trailer.put("Root", this.root);
final PdfDocumentInfo4a documentInfo = getDocumentInfo(false);
@@ -355,18 +306,13 @@
if (this.encryption != null) {
trailer.put("Encrypt", this.encryption);
}
-
- /* Write the trailer. */
- final ByteArrayBuilder builder = new ByteArrayBuilder();
- builder.append("trailer" + PdfObject.EOL);
- builder.append(getTrailer().serialize(this));
- builder.append("startxref");
- builder.append(PdfObject.EOL);
- builder.append(Long.toString(xrefPosition));
- builder.append(PdfObject.EOL);
- builder.append(PdfConstants.DOCUMENT_END_MARKER.toString() + PdfObject.EOL);
-
- builder.writeTo(output);
+ if (this.permanentFileId != null) {
+ final PdfArray array = trailer.ensureArray("ID");
+ array.ensureMinimumSize(2);
+ array.set(0, new PdfHexString(getPermanentFileId()));
+ array.set(1, new PdfHexString(getIncrementalFileId()));
+ }
+ return trailer;
}
/**
@@ -778,18 +724,6 @@
throws PdfException, IOException {
final PdfSerializer serializer = new PdfSerializer(this, output, config);
serializer.process();
-
- this.position = serializer.getPosition();
-
- /* Write the pages and other accumulated objects. */
- final PdfCrossRefInfo xrefInfo = writeIndirectObjects(output);
- writeDeferredIndirectObjects(output, xrefInfo);
-
- /* Remember position of xref table. */
- final long xrefPosition = this.position;
- xrefInfo.writeTable(output);
-
- writeTrailer(output, xrefPosition);
}
@Override
@@ -799,17 +733,6 @@
throw new UnsupportedOperationException();
}
- /**
- * Returns the file trailer, creating it if necessary.
- * @return the file trailer object.
- */
- public PdfTrailer getTrailer() {
- if (this.lazyTrailer == null) {
- this.lazyTrailer = new PdfTrailer();
- }
- return this.lazyTrailer;
- }
-
public List<PdfObject> getIndirectObjects() {
return this.indirectObjects;
}
@@ -839,4 +762,95 @@
return this.root.getNamedDestinations().get(name);
}
+ /**
+ * Indicates whether a given object ID is included in the "write last" list of indirect objects.
+ * @param objectId The object ID to be tested.
+ * @return True if and only if {@code objectId} is on the "write last" list of indirect objects.
+ */
+ public boolean isWriteLastIndirectObject(final int objectId) {
+ return this.indirectWriteLast.contains(objectId);
+ }
+
+ /**
+ * Returns an iterator over the "write last" indirect objects, which, because they are conceptually a stack, will
+ * iterate over them in reverse order.
+ * @return An iterator over the "write last" indirect objects.
+ */
+ public IntPrimitiveIterator getWriteLastIterator() {
+ return this.indirectWriteLast.iteratorReverse();
+ }
+
+ /**
+ * Returns the permanent document file ID.
+ * @return The permanent file ID.
+ * @see "PDFReference, Sixth Edition (PDF version 1.7), Section 10.3."
+ */
+ public ByteArray getPermanentFileId() {
+ return this.permanentFileId;
+ }
+
+ /**
+ * Creates a random permanent file ID for this document.
+ * @return The newly-created file ID.
+ * @throws IllegalStateException If this document already has a permanent file ID.
+ */
+ public ByteArray createPermanentFileId() {
+ if (this.permanentFileId != null) {
+ throw new IllegalStateException("Permanent file ID already exists.");
+ }
+ final byte[] fileIdBytes = new byte[PdfConstants.FILE_ID_SIZE];
+ final Random random = new Random();
+ random.nextBytes(fileIdBytes);
+ this.permanentFileId = new ByteArray(fileIdBytes);
+ return this.permanentFileId;
+ }
+
+ /**
+ * Sets the permanent document file ID.
+ * @param fileId The new value for the permanent document file ID.
+ * The size of the array must be exactly 16.
+ * @throws IllegalStateException If this document already has a permanent file ID.
+ * @see "PDFReference, Sixth Edition (PDF version 1.7), Section 10.3."
+ */
+ public void setPermanentFileId(final ByteArray fileId) {
+ if (this.permanentFileId != null) {
+ throw new IllegalStateException("Permanent file ID already exists.");
+ }
+ if (fileId.length() != PdfConstants.FILE_ID_SIZE) {
+ throw new IllegalArgumentException(
+ String.format("Size of array must be exactly {0}, actual: {1}",
+ PdfConstants.FILE_ID_SIZE, fileId.length()));
+ }
+ this.permanentFileId = fileId;
+ }
+
+ /**
+ * Returns the incremental document file ID.
+ * @return The incremental file ID.
+ * @see "PDFReference, Sixth Edition (PDF version 1.7), Section 10.3."
+ */
+ public ByteArray getIncrementalFileId() {
+ if (this.incrementalFileId == null) {
+ /* If not explicitly set, we assume that this is a new file, and the incremental file ID should be the same
+ * as the permanent one. */
+ this.incrementalFileId = this.permanentFileId;
+ }
+ return this.incrementalFileId;
+ }
+
+ /**
+ * Sets the incremental document file ID.
+ * @param fileId The new value for the incremental document file ID.
+ * The size of the array must be exactly 16.
+ * @see "PDFReference, Sixth Edition (PDF version 1.7), Section 10.3."
+ */
+ public void setIncrementalFileId(final ByteArray fileId) {
+ if (fileId.length() != PdfConstants.FILE_ID_SIZE) {
+ throw new IllegalArgumentException(
+ String.format("Size of array must be exactly {0}, actual: {1}",
+ PdfConstants.FILE_ID_SIZE, fileId.length()));
+ }
+ this.incrementalFileId = fileId;
+ }
+
}
Modified: trunk/foray/foray-pdf/src/main/java/org/foray/pdf/encrypt/PdfEncryption4a.java
===================================================================
--- trunk/foray/foray-pdf/src/main/java/org/foray/pdf/encrypt/PdfEncryption4a.java 2022-01-30 15:28:52 UTC (rev 12510)
+++ trunk/foray/foray-pdf/src/main/java/org/foray/pdf/encrypt/PdfEncryption4a.java 2022-01-30 17:02:34 UTC (rev 12511)
@@ -331,7 +331,7 @@
this.digest.update((byte) (permissions >>> WellKnownConstants.SHIFT_1_BYTE));
this.digest.update((byte) (permissions >>> WellKnownConstants.SHIFT_2_BYTES));
this.digest.update((byte) (permissions >>> WellKnownConstants.SHIFT_3_BYTES));
- this.digest.update(this.doc.getTrailer().getPermanentFileID().toArray());
+ this.digest.update(this.doc.getPermanentFileId().toArray());
final byte[] hash = this.digest.digest();
this.encryptionKey = new byte[PdfEncryption4a.DEFAULT_KEY_SIZE];
Modified: trunk/foray/foray-pdf/src/main/java/org/foray/pdf/serial/PdfSerializer.java
===================================================================
--- trunk/foray/foray-pdf/src/main/java/org/foray/pdf/serial/PdfSerializer.java 2022-01-30 15:28:52 UTC (rev 12510)
+++ trunk/foray/foray-pdf/src/main/java/org/foray/pdf/serial/PdfSerializer.java 2022-01-30 17:02:34 UTC (rev 12511)
@@ -29,13 +29,20 @@
package org.foray.pdf.serial;
import org.foray.common.primitive.ObjectUtils;
+import org.foray.common.sequence.ByteArrayBuilder;
+import org.foray.pdf.PdfConstants;
+import org.foray.pdf.PdfObjectReference;
import org.foray.pdf.document.PdfDocument4a;
+import org.foray.pdf.type.PdfObject;
+import org.axsl.pdf.PdfException;
import org.axsl.pdf.PdfSerializationConfig;
import org.axsl.utility.sequence.ByteSequencePlus;
+import org.axsl.utility.sequence.IntPrimitiveIterator;
import java.io.IOException;
import java.io.OutputStream;
+import java.util.List;
/**
* Serializes a {@link PdfDocument4a}.
@@ -86,16 +93,92 @@
* For the objects provided at construction, writes the serialized content of the document to the output stream
* using the configuration.
* @throws IOException For errors writing to the output stream.
+ * @throws PdfException For errors serializing the PDF content.
*/
- public void process() throws IOException {
+ public void process() throws IOException, PdfException {
/* TODO: Remove following line after config is used. */
ObjectUtils.noOperation(this.config);
final PdfHeader header = new PdfHeader(this.document.getVersion());
processBytes(header.serialize());
+
+ /* Write the pages and other indirect objects. */
+ final List<PdfObject> indirectObjects = this.document.getIndirectObjects();
+
+ final PdfCrossRefInfo xrefInfo = new PdfCrossRefInfo();
+ writeIndirectObjects(indirectObjects, xrefInfo);
+ writeDeferredIndirectObjects(indirectObjects, xrefInfo);
+
+ /* Remember position of xref table. */
+ final long xrefPosition = this.position;
+ xrefInfo.writeTable(output);
+
+ writeTrailer(output, xrefPosition);
}
+ private void writeIndirectObjects(final List<PdfObject> indirectObjects, final PdfCrossRefInfo xrefInfo)
+ throws PdfException {
+
+ /* Use a "while" loop here, because as each object is written, it has potential to reference another object
+ * indirectly, which will add an item to indirectObjects.
+ */
+ int objectId = 1;
+ while (objectId < indirectObjects.size()) {
+ final PdfObject object = indirectObjects.get(objectId);
+ if (object != null) {
+ final PdfObjectReference reference = object.getIndirectReference();
+ if (this.document.isWriteLastIndirectObject(reference.getNumber())) {
+ /* We are not serializing this object yet. */
+ } else {
+ /* Output the object and increment the character position by the object's length. */
+ final PdfCrossRefEntry xref = new PdfCrossRefEntry(object);
+ xref.setOffset(this.position);
+ xrefInfo.setTableEntry(reference.getNumber(), xref);
+ this.position += object.serialize(output, this.document);
+ }
+ }
+ objectId ++;
+ }
+ }
+
+ private void writeDeferredIndirectObjects(final List<PdfObject> indirectObjects, final PdfCrossRefInfo xrefInfo)
+ throws PdfException {
+ /* Treat the deferred items like a stack, and iterate in reverse order. */
+ final IntPrimitiveIterator deferredObjectIterator = this.document.getWriteLastIterator();
+ while (deferredObjectIterator.hasNext()) {
+ final int objectId = deferredObjectIterator.nextInt();
+ final PdfObject object = indirectObjects.get(objectId);
+ if (object != null) {
+ final PdfObjectReference reference = object.getIndirectReference();
+ final PdfCrossRefEntry xref = new PdfCrossRefEntry(object);
+ xref.setOffset(this.position);
+ xrefInfo.setTableEntry(reference.getNumber(), xref);
+ this.position += object.serialize(output, this.document);
+ }
+ }
+ }
+
/**
+ * Write the document trailer.
+ * @param output The output stream.
+ * @param xrefPosition The offset to the cross-reference table.
+ * @throws PdfException For errors while writing to the output stream.
+ */
+ private void writeTrailer(final OutputStream output, final long xrefPosition) throws PdfException, IOException {
+ /* Write the trailer. */
+ final ByteArrayBuilder builder = new ByteArrayBuilder();
+ builder.append("trailer" + PdfObject.EOL);
+ builder.append(this.document.getTrailer().serialize(this.document));
+ builder.append("startxref");
+ builder.append(PdfObject.EOL);
+ builder.append(Long.toString(xrefPosition));
+ builder.append(PdfObject.EOL);
+ builder.append(PdfConstants.DOCUMENT_END_MARKER.toString() + PdfObject.EOL);
+
+ builder.writeTo(output);
+ }
+
+ /**
* Writes a sequence of bytes to the output and adds the size to the position.
* @param bytes The bytes to be written.
* @throws IOException For errors writing to the output stream.
Modified: trunk/foray/foray-pdf/src/main/java/org/foray/pdf/serial/PdfTrailer.java
===================================================================
--- trunk/foray/foray-pdf/src/main/java/org/foray/pdf/serial/PdfTrailer.java 2022-01-30 15:28:52 UTC (rev 12510)
+++ trunk/foray/foray-pdf/src/main/java/org/foray/pdf/serial/PdfTrailer.java 2022-01-30 17:02:34 UTC (rev 12511)
@@ -28,15 +28,10 @@
package org.foray.pdf.serial;
-import org.foray.common.sequence.ByteArray;
-import org.foray.pdf.PdfConstants;
-import org.foray.pdf.type.PdfArray;
import org.foray.pdf.type.PdfDictionary;
-import org.foray.pdf.type.PdfHexString;
import java.util.Arrays;
import java.util.List;
-import java.util.Random;
public class PdfTrailer extends PdfDictionary {
@@ -68,85 +63,4 @@
return null;
}
- private ByteArray getStoredPermanentFileId() {
- final PdfArray idArray = this.getPdfArray("ID");
- if (idArray == null) {
- return null;
- }
- final PdfHexString hexString = idArray.getPdfHexString(0);
- return hexString == null ? null : hexString.getValue();
- }
-
- private ByteArray getStoredIncrementalFileId() {
- final PdfArray idArray = this.getPdfArray("ID");
- if (idArray == null) {
- return null;
- }
- final PdfHexString hexString = idArray.getPdfHexString(1);
- return hexString == null ? null : hexString.getValue();
- }
-
- /**
- * Returns the permanent document file ID.
- * @return The permanent file ID.
- * @see "PDFReference, Sixth Edition (PDF version 1.7), Section 10.3."
- */
- public ByteArray getPermanentFileID() {
- if (getStoredPermanentFileId() == null) {
- final byte[] fileIdBytes = new byte[PdfConstants.FILE_ID_SIZE];
- final Random random = new Random();
- random.nextBytes(fileIdBytes);
- setPermanentFileId(new ByteArray(fileIdBytes));
- }
- return getStoredPermanentFileId();
- }
-
- /**
- * Sets the permanent document file ID.
- * @param fileId The new value for the permanent document file ID.
- * The size of the array must be exactly 16.
- * @see "PDFReference, Sixth Edition (PDF version 1.7), Section 10.3."
- */
- public void setPermanentFileId(final ByteArray fileId) {
- if (fileId.length() != PdfConstants.FILE_ID_SIZE) {
- throw new IllegalArgumentException(
- String.format("Size of array must be exactly {0}, actual: {1}",
- PdfConstants.FILE_ID_SIZE, fileId.length()));
- }
- final PdfArray array = this.ensureArray("ID");
- array.ensureMinimumSize(2);
- array.set(0, new PdfHexString(fileId));
- }
-
- /**
- * Returns the incremental document file ID.
- * @return The incremental file ID.
- * @see "PDFReference, Sixth Edition (PDF version 1.7), Section 10.3."
- */
- public ByteArray getIncrementalFileID() {
- if (getStoredIncrementalFileId() == null) {
- /* If not explicitly set, we assume that this is a new file, and the incremental file ID should be the same
- * as the permanent one. */
- this.setIncrementalFileId(getPermanentFileID());
- }
- return getStoredIncrementalFileId();
- }
-
- /**
- * Sets the incremental document file ID.
- * @param fileId The new value for the incremental document file ID.
- * The size of the array must be exactly 16.
- * @see "PDFReference, Sixth Edition (PDF version 1.7), Section 10.3."
- */
- public void setIncrementalFileId(final ByteArray fileId) {
- if (fileId.length() != PdfConstants.FILE_ID_SIZE) {
- throw new IllegalArgumentException(
- String.format("Size of array must be exactly {0}, actual: {1}",
- PdfConstants.FILE_ID_SIZE, fileId.length()));
- }
- final PdfArray array = this.ensureArray("ID");
- array.ensureMinimumSize(2);
- array.set(1, new PdfHexString(fileId));
- }
-
}
Modified: trunk/foray/foray-pdf/src/test/java/org/foray/pdf/object/PdfDocumentTests.java
===================================================================
--- trunk/foray/foray-pdf/src/test/java/org/foray/pdf/object/PdfDocumentTests.java 2022-01-30 15:28:52 UTC (rev 12510)
+++ trunk/foray/foray-pdf/src/test/java/org/foray/pdf/object/PdfDocumentTests.java 2022-01-30 17:02:34 UTC (rev 12511)
@@ -80,8 +80,8 @@
final PsServer ps = null;
final PdfDocument4a doc = new PdfDocument4a(ps);
doc.setVersion(PdfVersion.VERSION_1_4);
- doc.getTrailer().setPermanentFileId(ByteArray.fromHexCharSequence("4397CDCC3F8F94FD6C77A64F83E95278"));
- doc.getTrailer().setIncrementalFileId(ByteArray.fromHexCharSequence("7CA33F3FFDF62A30122D7AAD3DA09789"));
+ doc.setPermanentFileId(ByteArray.fromHexCharSequence("4397CDCC3F8F94FD6C77A64F83E95278"));
+ doc.setIncrementalFileId(ByteArray.fromHexCharSequence("7CA33F3FFDF62A30122D7AAD3DA09789"));
final int widthPoints = 396; // 5.5in
final int heightPoints = 612; // 8.5in
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|