aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/pdf
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/org/apache/fop/pdf')
-rw-r--r--src/java/org/apache/fop/pdf/PDFAMode.java13
-rw-r--r--src/java/org/apache/fop/pdf/PDFArray.java9
-rw-r--r--src/java/org/apache/fop/pdf/PDFFactory.java28
-rw-r--r--src/java/org/apache/fop/pdf/PDFLink.java12
-rw-r--r--src/java/org/apache/fop/pdf/PDFPage.java17
-rw-r--r--src/java/org/apache/fop/pdf/PDFParentTree.java50
-rw-r--r--src/java/org/apache/fop/pdf/PDFProfile.java29
-rw-r--r--src/java/org/apache/fop/pdf/PDFRoot.java48
-rw-r--r--src/java/org/apache/fop/pdf/PDFStructElem.java176
-rw-r--r--src/java/org/apache/fop/pdf/PDFStructTreeRoot.java67
10 files changed, 441 insertions, 8 deletions
diff --git a/src/java/org/apache/fop/pdf/PDFAMode.java b/src/java/org/apache/fop/pdf/PDFAMode.java
index 1b433e66d..18c4a2489 100644
--- a/src/java/org/apache/fop/pdf/PDFAMode.java
+++ b/src/java/org/apache/fop/pdf/PDFAMode.java
@@ -44,7 +44,18 @@ public final class PDFAMode {
return this.name;
}
- /** @return true if this mode obey the restrictions established by PDF/A-1b. */
+ /**
+ * Indicates whether this mode obeys the restrictions established by PDF/A-1a.
+ * @return true if this mode obeys the restrictions established by PDF/A-1a.
+ */
+ public boolean isPDFA1LevelA() {
+ return (this != DISABLED);
+ }
+
+ /**
+ * Indicates whether this mode obeys the restrictions established by PDF/A-1b.
+ * @return true if this mode obeys the restrictions established by PDF/A-1b.
+ */
public boolean isPDFA1LevelB() {
return (this != DISABLED);
//PDF/A-1a is a superset of PDF/A-1b!
diff --git a/src/java/org/apache/fop/pdf/PDFArray.java b/src/java/org/apache/fop/pdf/PDFArray.java
index 7c5f8ba9b..a7dfc388e 100644
--- a/src/java/org/apache/fop/pdf/PDFArray.java
+++ b/src/java/org/apache/fop/pdf/PDFArray.java
@@ -107,6 +107,15 @@ public class PDFArray extends PDFObject {
}
/**
+ * Indicates whether the given object exists in the array.
+ * @param obj the object to look for
+ * @return true if obj is contained
+ */
+ public boolean contains(Object obj) {
+ return this.values.contains(obj);
+ }
+
+ /**
* Returns the length of the array
* @return the length of the array
*/
diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java
index a8d7a0702..db2e99875 100644
--- a/src/java/org/apache/fop/pdf/PDFFactory.java
+++ b/src/java/org/apache/fop/pdf/PDFFactory.java
@@ -179,13 +179,26 @@ public class PDFFactory {
* @param cropBox the CropBox area
* @param bleedBox the BleedBox area
* @param trimBox the TrimBox area
+ * @param currentPageParentKey the integer key in the structural parent tree
*
* @return the created /Page object
*/
public PDFPage makePage(PDFResources resources, int pageIndex,
Rectangle2D mediaBox, Rectangle2D cropBox,
- Rectangle2D bleedBox, Rectangle2D trimBox) {
+ Rectangle2D bleedBox, Rectangle2D trimBox,
+ int currentPageParentKey) {
+ /*
+ * create a PDFPage with the next object number, the given
+ * resources, contents and dimensions
+ */
PDFPage page = new PDFPage(resources, pageIndex, mediaBox, cropBox, bleedBox, trimBox);
+ if (currentPageParentKey > -1) {
+ //Accessibility is enabled
+ page.setStructParents(currentPageParentKey);
+ //This is a PDF 1.5 feature. It is set as a work-around for a bug in Adobe Acrobat
+ //which reports this missing even if the PDF file is PDF 1.4.
+ page.setTabs(new PDFName("S"));
+ }
getDocument().assignObjectNumber(page);
getDocument().getPages().addPage(page);
@@ -207,7 +220,7 @@ public class PDFFactory {
public PDFPage makePage(PDFResources resources,
int pageWidth, int pageHeight, int pageIndex) {
Rectangle2D mediaBox = new Rectangle2D.Double(0, 0, pageWidth, pageHeight);
- return makePage(resources, pageIndex, mediaBox, mediaBox, mediaBox, mediaBox);
+ return makePage(resources, pageIndex, mediaBox, mediaBox, mediaBox, mediaBox, -1);
}
/**
@@ -883,6 +896,17 @@ public class PDFFactory {
}
/**
+ * Creates and returns a StructTreeRoot object. Used for accessibility.
+ * @return structure Tree Root element
+ */
+ public PDFStructTreeRoot makeStructTreeRoot() {
+ PDFStructTreeRoot structTreeRoot = new PDFStructTreeRoot();
+ getDocument().assignObjectNumber(structTreeRoot);
+ getDocument().addTrailerObject(structTreeRoot);
+ return structTreeRoot;
+ }
+
+ /**
* Make a the head object of the name dictionary (the /Dests object).
*
* @param destinationList a list of PDFDestination instances
diff --git a/src/java/org/apache/fop/pdf/PDFLink.java b/src/java/org/apache/fop/pdf/PDFLink.java
index 6f5ffeb0d..66791e3ba 100644
--- a/src/java/org/apache/fop/pdf/PDFLink.java
+++ b/src/java/org/apache/fop/pdf/PDFLink.java
@@ -42,6 +42,7 @@ public class PDFLink extends PDFObject {
private float bry;
private String color;
private PDFAction action;
+ private Integer structParent;
/**
* create objects associated with a link annotation (GoToR)
@@ -68,6 +69,15 @@ public class PDFLink extends PDFObject {
this.action = action;
}
+
+ /**
+ * Used for accessibility
+ * @param mcid of this structParent
+ */
+ public void setStructParent(int mcid) {
+ this.structParent = new Integer(mcid);
+ }
+
/**
* {@inheritDoc}
*/
@@ -87,6 +97,8 @@ public class PDFLink extends PDFObject {
+ (brx) + " " + (bry) + " ]\n" + "/C [ "
+ this.color + " ]\n" + "/Border [ 0 0 0 ]\n" + "/A "
+ this.action.getAction() + "\n" + "/H /I\n"
+ + (this.structParent != null
+ ? "/StructParent " + this.structParent.toString() + "\n" : "")
+ fFlag + "\n>>\nendobj\n";
return s;
}
diff --git a/src/java/org/apache/fop/pdf/PDFPage.java b/src/java/org/apache/fop/pdf/PDFPage.java
index 4fa3b0a09..1bcaa65c6 100644
--- a/src/java/org/apache/fop/pdf/PDFPage.java
+++ b/src/java/org/apache/fop/pdf/PDFPage.java
@@ -154,4 +154,21 @@ public class PDFPage extends PDFResourceContext {
return this.pageIndex;
}
+ /**
+ * Sets the "StructParents" value.
+ * @param structParents the integer key of this object's entry in the structural parent tree.
+ */
+ public void setStructParents(int structParents) {
+ put("StructParents", structParents);
+ }
+
+ /**
+ * Specifies the tab order for annotations on a page.
+ * @param value one of the allowed values (see PDF 1.5)
+ * @since PDF 1.5
+ */
+ public void setTabs(PDFName value) {
+ put("Tabs", value);
+ }
+
}
diff --git a/src/java/org/apache/fop/pdf/PDFParentTree.java b/src/java/org/apache/fop/pdf/PDFParentTree.java
new file mode 100644
index 000000000..7528aa299
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFParentTree.java
@@ -0,0 +1,50 @@
+/*
+ * 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 /ParentTree
+ */
+public class PDFParentTree extends PDFNumberTreeNode {
+
+ /**
+ * Create the /ParentTree NumberTreeNode
+ */
+ public PDFParentTree() {
+ super();
+ }
+
+ /**
+ * Get the parentTree.
+ * @return parentTree as PDFNumsArray
+ */
+ public PDFNumsArray getNums() {
+ PDFNumsArray nums = super.getNums();
+ if (nums == null) {
+ nums = new PDFNumsArray(this);
+ setNums(nums);
+ }
+ return nums;
+ }
+}
+
+
+
+
diff --git a/src/java/org/apache/fop/pdf/PDFProfile.java b/src/java/org/apache/fop/pdf/PDFProfile.java
index 20af4e212..b645cb825 100644
--- a/src/java/org/apache/fop/pdf/PDFProfile.java
+++ b/src/java/org/apache/fop/pdf/PDFProfile.java
@@ -58,9 +58,6 @@ public class PDFProfile {
*/
protected void validateProfileCombination() {
if (pdfAMode != PDFAMode.DISABLED) {
- if (pdfAMode == PDFAMode.PDFA_1A) {
- throw new UnsupportedOperationException("PDF/A-1a is not implemented, yet");
- }
if (pdfAMode == PDFAMode.PDFA_1B) {
if (pdfXMode != PDFXMode.DISABLED && pdfXMode != PDFXMode.PDFX_3_2003) {
throw new PDFConformanceException(
@@ -192,6 +189,32 @@ public class PDFProfile {
}
}
+ /**
+ * Checks a few things required for tagged PDF.
+ */
+ public void verifyTaggedPDF() {
+ if (getPDFAMode().isPDFA1LevelA()) {
+ final String err = "{0} requires the {1} dictionary entry to be set";
+ PDFDictionary markInfo = getDocument().getRoot().getMarkInfo();
+ if (markInfo == null) {
+ throw new PDFConformanceException(format(
+ "{0} requires the MarkInfo dictionary to be present", getPDFAMode()));
+ }
+ if (!Boolean.TRUE.equals(markInfo.get("Marked"))) {
+ throw new PDFConformanceException(format(err,
+ new Object[] {getPDFAMode(), "Marked"}));
+ }
+ if (getDocument().getRoot().getStructTreeRoot() == null) {
+ throw new PDFConformanceException(format(err,
+ new Object[] {getPDFAMode(), "StructTreeRoot"}));
+ }
+ if (getDocument().getRoot().getLanguage() == null) {
+ throw new PDFConformanceException(format(err,
+ new Object[] {getPDFAMode(), "Lang"}));
+ }
+ }
+ }
+
/** @return true if the ID entry must be present in the trailer. */
public boolean isIDEntryRequired() {
return isPDFAActive() || isPDFXActive();
diff --git a/src/java/org/apache/fop/pdf/PDFRoot.java b/src/java/org/apache/fop/pdf/PDFRoot.java
index 1ea316390..3057a9e4d 100644
--- a/src/java/org/apache/fop/pdf/PDFRoot.java
+++ b/src/java/org/apache/fop/pdf/PDFRoot.java
@@ -19,6 +19,9 @@
package org.apache.fop.pdf;
+import java.io.IOException;
+import java.io.OutputStream;
+
/**
* Class representing a Root (/Catalog) object.
*/
@@ -56,18 +59,24 @@ public class PDFRoot extends PDFDictionary {
* object must be created before the PDF document is
* generated, but it is not assigned an object ID until
* it is about to be written (immediately before the xref
- * table as part of the trsailer). (mark-fop@inomial.com)
+ * table as part of the trailer). (mark-fop@inomial.com)
*
* @param objnum the object's number
* @param pages the PDFPages object
*/
public PDFRoot(int objnum, PDFPages pages) {
super();
- setObjectNumber(objnum);
+ setObjectNumber(objnum);
put("Type", new PDFName("Catalog"));
setRootPages(pages);
}
+ /** {@inheritDoc} */
+ protected int output(OutputStream stream) throws IOException {
+ getDocument().getProfile().verifyTaggedPDF();
+ return super.output(stream);
+ }
+
/**
* Set the page mode for the PDF document.
*
@@ -252,4 +261,39 @@ public class PDFRoot extends PDFDictionary {
put("Lang", lang);
}
+ /**
+ * Sets the StructTreeRoot object. Used for accessibility.
+ * @param structTreeRoot of this document
+ */
+ public void setStructTreeRoot(PDFStructTreeRoot structTreeRoot) {
+ if (structTreeRoot == null) {
+ throw new NullPointerException("structTreeRoot must not be null");
+ }
+ put("StructTreeRoot", structTreeRoot);
+ }
+
+ /**
+ * Returns the StructTreeRoot object.
+ * @return the structure tree root (or null if accessibility is not enabled)
+ */
+ public PDFStructTreeRoot getStructTreeRoot() {
+ return (PDFStructTreeRoot)get("StructTreeRoot");
+ }
+
+ /**
+ * Marks this document as conforming to the Tagged PDF conventions.
+ */
+ public void makeTagged() {
+ PDFDictionary dict = new PDFDictionary();
+ dict.put("Marked", Boolean.TRUE);
+ put("MarkInfo", dict); //new PDFMarkInfo()
+ }
+
+ /**
+ * Returns the MarkInfo dictionary.
+ * @return the MarkInfo dictionary (or null if it's not present)
+ */
+ public PDFDictionary getMarkInfo() {
+ return (PDFDictionary)get("MarkInfo");
+ }
}
diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java
new file mode 100644
index 000000000..2f8898a19
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFStructElem.java
@@ -0,0 +1,176 @@
+/*
+ * 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.util.Locale;
+
+import org.apache.fop.util.XMLUtil;
+
+/**
+ * Class representing a PDF Structure Element.
+ */
+public class PDFStructElem extends PDFDictionary {
+
+ private PDFObject parentObject = null;
+ private boolean level1 = false;
+
+ /**
+ * Create the /StructTreeRoot dictionary
+ * @param parent Parent of this PDFStructElem
+ * @param structureType the structure type for the element
+ */
+ public PDFStructElem(PDFObject parent, PDFName structureType) {
+ super();
+ if (parent instanceof PDFStructElem) {
+ parentObject = (PDFStructElem) parent;
+ }
+ put("Type", new PDFName("StructElem"));
+ setStructureType(structureType);
+ setParent(parent);
+ }
+
+ /**
+ * This method is called for PDFStructElements which are direct children of
+ * fo:static-content or fo:flow-section
+ */
+ public void setLevel1() {
+ this.level1 = true;
+ }
+
+ /**
+ *
+ * @return true if the PDFStructElement is a direct child of
+ * fo:static-content or fo:flow-section
+ */
+ public boolean getLevel1() {
+ return this.level1;
+ }
+
+ /**
+ * Get the parent
+ * @return PDFStructElem of parent
+ */
+ public PDFObject getParentStructElem() {
+ return (PDFStructElem)this.parentObject;
+ }
+
+ /**
+ * Set the parent for this StructElem
+ * @param parent to be added
+ */
+ public void setParent(PDFObject parent) {
+ if (parent != null) {
+ put("P", new PDFReference(parent));
+ }
+ }
+
+ /**
+ * The kids of this StructElem
+ * @return the kids
+ */
+ public PDFArray getKids() {
+ return (PDFArray)get("K");
+ }
+
+ /**
+ * Add a kid to this strucElem
+ * @param kid to be added
+ */
+ public void addKid(PDFObject kid) {
+ PDFArray kids = getKids();
+ if (kids == null) {
+ kids = new PDFArray();
+ put("K", kids);
+ }
+ kids.add(kid);
+ }
+
+ /**
+ * Add a kid, but only if it does not already exist.
+ * @param kid to be added
+ * @return true if kid did not already exist
+ */
+ public boolean addUniqueKid(PDFObject kid) {
+ PDFArray mArray = getKids();
+ if (mArray == null || !mArray.contains(kid)) {
+ addKid(kid);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Add kid referenced through mcid integer. Used for images.
+ * @param mcid of this kid
+ */
+ public void addMCIDKid(int mcid) {
+ put("K", mcid);
+ }
+
+ /**
+ * Add a page reference to this structElem
+ * @param pageObject to be added
+ */
+ public void addPage(Object pageObject) {
+ put("Pg", (PDFObject) pageObject);
+ }
+
+ /**
+ * Sets the structure type (the "S" entry).
+ * @param type the structure type
+ */
+ public void setStructureType(PDFName type) {
+ put("S", type);
+ }
+
+ /**
+ * Returns the structure type of this structure element.
+ * @return the structure type
+ */
+ public PDFName getStructureType() {
+ return (PDFName)get("S");
+ }
+
+ /**
+ * Sets the language of this structure element.
+ * @param language the language (as defined in the section about
+ * "Natural Language Specification")
+ */
+ public void setLanguage(String language) {
+ put("Lang", language);
+ }
+
+ /**
+ * Sets the language of this structure element.
+ * @param language the language
+ */
+ public void setLanguage(Locale language) {
+ setLanguage(XMLUtil.toRFC3066(language));
+ }
+
+ /**
+ * Returns the language of this structure element.
+ * @return the language (or null if no language was specified)
+ */
+ public String getLanguage() {
+ return (String)get("Lang");
+ }
+}
diff --git a/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java
new file mode 100644
index 000000000..e530b1582
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java
@@ -0,0 +1,67 @@
+/*
+ * 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 /StructTreeRoot dictionary.
+ */
+public class PDFStructTreeRoot extends PDFDictionary {
+
+ /**
+ * Create the /StructTreeRoot dictionary.
+ */
+ public PDFStructTreeRoot() {
+ super();
+ put("Type", new PDFName("StructTreeRoot"));
+ put("K", new PDFArray());
+ }
+
+ /**
+ * Add parentTree entry.
+ * @param parentTree to be added
+ */
+ public void addParentTree(PDFParentTree parentTree) {
+ put("ParentTree", parentTree);
+ }
+
+ /**
+ * Get the kids.
+ * @return the kids
+ */
+ public PDFArray getKids() {
+ return (PDFArray)get("K");
+ }
+
+ /**
+ * Returns the first child of the kids array (normally the structure tree root element)
+ * @return the first child
+ */
+ public PDFObject getFirstChild() {
+ return (PDFObject)getKids().get(0);
+ }
+
+ /**
+ * Adds a kid.
+ * @param kid to be added
+ */
+ public void addKid(PDFObject kid) {
+ getKids().add(kid);
+ }
+} \ No newline at end of file