Browse Source

FOP-1722: Values in PDF Number Trees must be indirect references by Dave Roxburgh

tags/2_9
Simon Steiner 1 year ago
parent
commit
120b50fdf6

+ 71
- 1
fop-core/src/main/java/org/apache/fop/pdf/PDFNumsArray.java View File

@@ -50,13 +50,83 @@ public class PDFNumsArray extends PDFObject {
return this.map.size();
}

/**
* Determines whether a value object should be converted to an indirect reference for inclusion in a Number Tree
* array according to the PDF spec.
* PDF1.0 - 1.2 - Spec is silent on this subject (as Number Trees don't exist).
* PDF1.3 & 1.4 - Values must be indirect object refs.
* PDF1.5 - Recommended: stream, dictionary, array, and string values be indirect object refs.
* PDF1.6 - 2.0 - Stream values must be indirect object refs.
* Recommended: dictionary, array, and string values be indirect object refs.
* Method signals for values that must be, and those recommended to be indirect object refs.
* @param obj The object to be considered.
* @return True iff the object should be converted.
*/
private boolean shouldConvertToRef(PDFObject obj) {
boolean retval = false;
if (getDocument() != null && getDocument().getPDFVersion() != null) {
switch (getDocument().getPDFVersion()) {
case V1_0: // fall-through
case V1_1: // fall-through
case V1_2:
log.error("Number Tree used in PDF version " + getDocument().getPDFVersion());
break;
case V1_3: // fall-through
case V1_4:
retval = true;
break;
case V1_5: // fall-through
case V1_6: // fall-through
case V1_7: // fall-through
case V2_0:
if (obj instanceof PDFStream
|| obj instanceof PDFDictionary
|| obj instanceof PDFArray
|| obj instanceof PDFText) {
retval = true;
}
break;
default:
log.error("Unrecognised PDF version " + getDocument().getPDFVersion());
break;
}
}
return retval;
}

/**
* This method provides conformance with the different PDF specs which require or recommend different types be used
* for Number Tree array values. Method indirects objects where indicated.
* @param obj The object to be considered for indirection.
* @return Either the object or a reference to the object.
*/
private Object indirectIfReq(Object obj) {
PDFDocument doc = getDocument();
Object retval = obj;
if (obj instanceof PDFObject) {
PDFObject pdfObj = (PDFObject) obj;
PDFObject parent = pdfObj.getParent();
if (shouldConvertToRef(pdfObj)) {
if (!pdfObj.hasObjectNumber()) { // Needs registering with the doc.
pdfObj.setParent(null); // Can't register if it has a parent.
pdfObj = doc.registerObject(pdfObj);
if (parent != null) {
pdfObj.setParent(parent); // Reinstate original parent.
}
}
retval = pdfObj.makeReference();
}
}
return retval;
}

/**
* Sets an entry.
* @param key the key of the value to set
* @param obj the new value
*/
public void put(Integer key, Object obj) {
this.map.put(key, obj);
this.map.put(key, indirectIfReq(obj));
}

/**

+ 0
- 8
fop-core/src/main/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java View File

@@ -119,14 +119,6 @@ public class PDFLogicalStructureHandler {
* Receive notification of the end of the current page.
*/
void endPage() {
// TODO
// Values in a number tree must be indirect references to the PDF
// objects associated to the keys. To enforce that the array is
// registered to the PDF document. Unfortunately that can't be done
// earlier since a call to PDFContentGenerator.flushPDFDoc can be made
// before the array is complete, which would result in only part of it
// being output to the PDF.
// This should really be handled by PDFNumsArray
pdfDoc.registerObject(pageParentTreeArray);
parentTree.addToNums(currentPage.getStructParents(), pageParentTreeArray);
}

+ 1
- 0
fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java View File

@@ -40,6 +40,7 @@ import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileAttachmentTestCase;
PDFDocumentTestCase.class,
PDFNullTestCase.class,
PDFNumsArrayTestCase.class,
PDFNumsArrayPDFV17TestCase.class,
PDFRectangleTestCase.class,
PDFReferenceTestCase.class,
PDFResourcesTestCase.class,

+ 12
- 5
fop-core/src/test/java/org/apache/fop/pdf/PDFNumsArrayTestCase.java View File

@@ -25,20 +25,25 @@ import org.junit.Before;
import org.junit.Test;

/**
* Test case for {@link PDFNumsArray}.
* Test case for {@link PDFNumsArray}. Uses default PDF doc (version 1.4) - requires text values and number values to be
* included as refs.
*/
public class PDFNumsArrayTestCase extends PDFObjectTestCase {
private static final String TEST_NAME = "Test name";
private static final int TEST_NUMBER = 10;
private PDFNumsArray numsArray;
private String expectedString = "[0 /Test#20name 1 10]";
private String expectedString = "[0 1 0 R 1 2 0 R]";
private String expectedStringName = "/Test#20name";
private String expectedStringNumber = Integer.valueOf(TEST_NUMBER).toString();

@Before
public void setUp() {
numsArray = new PDFNumsArray(parent);
numsArray.put(0, new PDFName("Test name"));
numsArray.setDocument(doc);
numsArray.put(0, new PDFName(TEST_NAME));
PDFNumber num = new PDFNumber();
num.setNumber(10);
num.setNumber(TEST_NUMBER);
numsArray.put(1, num);
numsArray.setDocument(doc);

pdfObjectUnderTest = numsArray;
}
@@ -50,5 +55,7 @@ public class PDFNumsArrayTestCase extends PDFObjectTestCase {
@Test
public void testOutput() throws IOException {
testOutputStreams(expectedString, numsArray);
testOutputStreams(expectedStringName, doc.objects.get(1));
testOutputStreams(expectedStringNumber, doc.objects.get(2));
}
}

+ 3
- 3
fop-core/src/test/java/org/apache/fop/pdf/PDFParentTreeTestCase.java View File

@@ -24,7 +24,7 @@ import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;

/**
* Tests that the nums array in the ParentTree dictionary is correctly being split into
@@ -76,7 +76,7 @@ public class PDFParentTreeTestCase {
*/
@Test
public void testOutOfOrderSplit() throws Exception {
PDFStructElem structElem = mock(PDFStructElem.class);
PDFStructElem structElem = spy(PDFStructElem.class);
for (int num = 50; num < 53; num++) {
parentTree.addToNums(num, structElem);
}
@@ -98,7 +98,7 @@ public class PDFParentTreeTestCase {
* @throws Exception
*/
private int getArrayNumber(int elementNumber) throws Exception {
PDFStructElem structElem = mock(PDFStructElem.class);
PDFStructElem structElem = spy(PDFStructElem.class);
for (int structParent = 0; structParent < elementNumber; structParent++) {
parentTree.addToNums(structParent, structElem);
}

Loading…
Cancel
Save