diff options
Diffstat (limited to 'src/java/org/apache/fop/pdf')
-rw-r--r-- | src/java/org/apache/fop/pdf/PDFAMode.java | 13 | ||||
-rw-r--r-- | src/java/org/apache/fop/pdf/PDFArray.java | 9 | ||||
-rw-r--r-- | src/java/org/apache/fop/pdf/PDFFactory.java | 28 | ||||
-rw-r--r-- | src/java/org/apache/fop/pdf/PDFLink.java | 12 | ||||
-rw-r--r-- | src/java/org/apache/fop/pdf/PDFPage.java | 17 | ||||
-rw-r--r-- | src/java/org/apache/fop/pdf/PDFParentTree.java | 50 | ||||
-rw-r--r-- | src/java/org/apache/fop/pdf/PDFProfile.java | 29 | ||||
-rw-r--r-- | src/java/org/apache/fop/pdf/PDFRoot.java | 48 | ||||
-rw-r--r-- | src/java/org/apache/fop/pdf/PDFStructElem.java | 176 | ||||
-rw-r--r-- | src/java/org/apache/fop/pdf/PDFStructTreeRoot.java | 67 |
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 |