*/
protected void writeDictionary(StringBuffer sb) {
sb.append("<<");
+ boolean compact = (this.order.size() <= 2);
Iterator iter = this.order.iterator();
while (iter.hasNext()) {
String key = (String)iter.next();
- sb.append("\n /");
- sb.append(key);
- sb.append(" ");
+ if (compact) {
+ sb.append(' ');
+ } else {
+ sb.append("\n ");
+ }
+ sb.append('/').append(key);
+ sb.append(' ');
Object obj = this.entries.get(key);
formatObject(obj, sb);
}
- sb.append("\n>>\n");
+ if (compact) {
+ sb.append(' ');
+ } else {
+ sb.append('\n');
+ }
+ sb.append(">>\n");
}
}
return names;
}
+ /**
+ * Make a names dictionary (the /PageLabels object).
+ * @return the new PDFPageLabels object
+ */
+ public PDFPageLabels makePageLabels() {
+ PDFPageLabels pageLabels = new PDFPageLabels();
+ getDocument().assignObjectNumber(pageLabels);
+ getDocument().addTrailerObject(pageLabels);
+ return pageLabels;
+ }
+
/**
* Make a the head object of the name dictionary (the /Dests object).
*
--- /dev/null
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+package org.apache.fop.pdf;\r
+\r
+/**\r
+ * Class representing a PDF number tree node.\r
+ */\r
+public class PDFNumberTreeNode extends PDFDictionary {\r
+\r
+ private static final String KIDS = "Kids";\r
+ private static final String NUMS = "Nums";\r
+ private static final String LIMITS = "Limits";\r
+\r
+ /**\r
+ * create a named destination\r
+ */\r
+ public PDFNumberTreeNode() {\r
+ /* generic creation of PDF object */\r
+ super();\r
+ }\r
+\r
+ /**\r
+ * Sets the Kids array.\r
+ * @param kids the Kids array\r
+ */\r
+ public void setKids(PDFArray kids) {\r
+ put(KIDS, kids);\r
+ }\r
+ \r
+ /**\r
+ * Returns the Kids array.\r
+ * @return the Kids array\r
+ */\r
+ public PDFArray getKids() {\r
+ return (PDFArray)get(KIDS);\r
+ }\r
+ \r
+ /**\r
+ * Sets the Nums array.\r
+ * @param nums the Nums array\r
+ */\r
+ public void setNums(PDFNumsArray nums) {\r
+ put(NUMS, nums);\r
+ }\r
+ \r
+ /**\r
+ * Returns the Nums array.\r
+ * @return the Nums array\r
+ */\r
+ public PDFNumsArray getNums() {\r
+ return (PDFNumsArray)get(NUMS);\r
+ }\r
+ \r
+ /**\r
+ * Sets the lower limit value of the Limits array.\r
+ * @param key the lower limit value\r
+ */\r
+ public void setLowerLimit(Integer key) {\r
+ PDFArray limits = prepareLimitsArray();\r
+ limits.set(0, key);\r
+ }\r
+\r
+ /**\r
+ * Returns the lower limit value of the Limits array.\r
+ * @return the lower limit value\r
+ */\r
+ public Integer getLowerLimit() {\r
+ PDFArray limits = prepareLimitsArray();\r
+ return (Integer)limits.get(0);\r
+ }\r
+\r
+ /**\r
+ * Sets the upper limit value of the Limits array.\r
+ * @param key the upper limit value\r
+ */\r
+ public void setUpperLimit(Integer key) {\r
+ PDFArray limits = prepareLimitsArray();\r
+ limits.set(1, key);\r
+ }\r
+\r
+ /**\r
+ * Returns the upper limit value of the Limits array.\r
+ * @return the upper limit value\r
+ */\r
+ public Integer getUpperLimit() {\r
+ PDFArray limits = prepareLimitsArray();\r
+ return (Integer)limits.get(1);\r
+ }\r
+\r
+\r
+ private PDFArray prepareLimitsArray() {\r
+ PDFArray limits = (PDFArray)get(LIMITS);\r
+ if (limits == null) {\r
+ limits = new PDFArray(new Object[2]);\r
+ put(LIMITS, limits);\r
+ }\r
+ if (limits.length() != 2) {\r
+ throw new IllegalStateException("Limits array must have 2 entries");\r
+ }\r
+ return limits;\r
+ }\r
+ \r
+}\r
+\r
--- /dev/null
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* $Id: PDFArray.java 588547 2007-10-26 07:48:14Z jeremias $ */\r
+ \r
+package org.apache.fop.pdf;\r
+\r
+import java.util.Iterator;\r
+import java.util.Map;\r
+import java.util.SortedMap;\r
+\r
+/**\r
+ * Class representing an "Nums" array object (for Number Trees).\r
+ */\r
+public class PDFNumsArray extends PDFObject {\r
+ \r
+ /** Sorted Map holding the values of this array. */\r
+ protected SortedMap map = new java.util.TreeMap();\r
+\r
+ /**\r
+ * Create a new, empty array object\r
+ */\r
+ public PDFNumsArray() {\r
+ /* generic creation of PDF object */\r
+ super();\r
+ }\r
+\r
+ /**\r
+ * Returns the length of the array\r
+ * @return the length of the array\r
+ */\r
+ public int length() {\r
+ return this.map.size();\r
+ }\r
+ \r
+ /**\r
+ * Sets an entry.\r
+ * @param key the key of the value to set\r
+ * @param obj the new value\r
+ */\r
+ public void put(int key, Object obj) {\r
+ this.map.put(new Integer(key), obj);\r
+ }\r
+ \r
+ /**\r
+ * Gets an entry.\r
+ * @param key the key of requested value\r
+ * @return the requested value\r
+ */\r
+ public Object get(int key) {\r
+ return this.map.get(new Integer(key));\r
+ }\r
+ \r
+ /** {@inheritDoc} */\r
+ public String toPDFString() {\r
+ StringBuffer p = new StringBuffer(64);\r
+ if (hasObjectNumber()) {\r
+ p.append(getObjectID());\r
+ }\r
+ p.append("[");\r
+ boolean first = true;\r
+ Iterator iter = this.map.entrySet().iterator();\r
+ while (iter.hasNext()) {\r
+ Map.Entry entry = (Map.Entry)iter.next();\r
+ if (!first) {\r
+ p.append(" ");\r
+ }\r
+ first = false;\r
+ formatObject(entry.getKey(), p);\r
+ p.append(" ");\r
+ formatObject(entry.getValue(), p);\r
+ }\r
+ p.append("]");\r
+ if (hasObjectNumber()) {\r
+ p.append("\nendobj\n");\r
+ }\r
+ return p.toString();\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* $Id$ */\r
+ \r
+package org.apache.fop.pdf;\r
+\r
+/**\r
+ * Class representing a PDF /PageLabels dictionary.\r
+ */\r
+public class PDFPageLabels extends PDFNumberTreeNode {\r
+ \r
+ /**\r
+ * Create the /PageLabels dictionary\r
+ */\r
+ public PDFPageLabels() {\r
+ super();\r
+ }\r
+\r
+ /**\r
+ * Returns the Nums object\r
+ * @return the Nums object (an empty PDFNumsArray for the "/Nums" entry is created\r
+ * if it doesn't exist)\r
+ */\r
+ public PDFNumsArray getNums() {\r
+ PDFNumsArray nums = super.getNums();\r
+ if (nums == null) {\r
+ nums = new PDFNumsArray();\r
+ setNums(nums);\r
+ }\r
+ return nums;\r
+ }\r
+ \r
+}\r
package org.apache.fop.pdf;
-import java.util.List;
-
/**
- * class representing a Root (/Catalog) object
+ * Class representing a Root (/Catalog) object.
*/
-public class PDFRoot extends PDFObject {
+public class PDFRoot extends PDFDictionary {
/**
* Use no page mode setting, default
*/
public static final int PAGEMODE_FULLSCREEN = 3;
- /**
- * the /Pages object that is root of the Pages hierarchy
- */
- protected PDFPages rootPages;
-
- /**
- * Root outline object
- */
- private PDFOutline outline;
-
- /** Optional Metadata object */
- private PDFMetadata metadata;
+ private static final PDFName[] PAGEMODE_NAMES = new PDFName[] {
+ new PDFName("UseNone"),
+ new PDFName("UseOutlines"),
+ new PDFName("UseThumbs"),
+ new PDFName("FullScreen"),
+ };
- /** The array of OutputIntents */
- private List outputIntents;
-
- /** the /Dests object, if this PDF has a Names Dictionary */
- private PDFNames names;
-
- private int pageMode = PAGEMODE_USENONE;
-
/**
* create a Root (/Catalog) object. NOTE: The PDFRoot
* object must be created before the PDF document is
public PDFRoot(int objnum, PDFPages pages) {
super();
setObjectNumber(objnum);
+ put("Type", new PDFName("Catalog"));
setRootPages(pages);
}
/**
* Set the page mode for the PDF document.
*
- * @param mode the page mode
+ * @param mode the page mode (one of PAGEMODE_*)
*/
public void setPageMode(int mode) {
- pageMode = mode;
+ put("PageMode", PAGEMODE_NAMES[mode]);
}
+ /**
+ * Returns the currently active /PageMode.
+ * @return the /PageMode (one of PAGEMODE_*)
+ */
+ public int getPageMode() {
+ PDFName mode = (PDFName)get("PageMode");
+ if (mode != null) {
+ for (int i = 0; i < PAGEMODE_NAMES.length; i++) {
+ if (PAGEMODE_NAMES[i].equals(mode)) {
+ return i;
+ }
+ }
+ throw new IllegalStateException("Unknown /PageMode encountered: " + mode);
+ } else {
+ return PAGEMODE_USENONE;
+ }
+ }
+
/**
* add a /Page object to the root /Pages object
*
* @param page the /Page object to add
*/
public void addPage(PDFPage page) {
- this.rootPages.addPage(page);
+ PDFPages pages = getRootPages();
+ pages.addPage(page);
}
/**
* @param pages the /Pages object to set as root
*/
public void setRootPages(PDFPages pages) {
- this.rootPages = pages;
+ put("Pages", pages.makeReference());
}
+ /**
+ * Returns the /PageLabels object.
+ * @return the /PageLabels object if set, null otherwise.
+ * @since PDF 1.3
+ */
+ public PDFPages getRootPages() {
+ PDFReference ref = (PDFReference)get("Pages");
+ return (ref != null ? (PDFPages)ref.getObject() : null);
+ }
+
+ /**
+ * Sets the /PageLabels object.
+ * @param pageLabels the /PageLabels object
+ */
+ public void setPageLabels(PDFPageLabels pageLabels) {
+ put("PageLabels", pageLabels.makeReference());
+ }
+
+ /**
+ * Returns the /PageLabels object.
+ * @return the /PageLabels object if set, null otherwise.
+ * @since PDF 1.3
+ */
+ public PDFPageLabels getPageLabels() {
+ PDFReference ref = (PDFReference)get("PageLabels");
+ return (ref != null ? (PDFPageLabels)ref.getObject() : null);
+ }
+
/**
* Set the root outline for the PDF document.
*
* @param out the root PDF Outline
*/
public void setRootOutline(PDFOutline out) {
- outline = out;
+ put("Outlines", out.makeReference());
+
+ //Set /PageMode to /UseOutlines by default if no other mode has been set
+ PDFName mode = (PDFName)get("PageMode");
+ if (mode == null) {
+ setPageMode(PAGEMODE_USEOUTLINES);
+ }
}
/**
* @return the root PDF Outline
*/
public PDFOutline getRootOutline() {
- return outline;
+ PDFReference ref = (PDFReference)get("Outlines");
+ return (ref != null ? (PDFOutline)ref.getObject() : null);
}
/**
- * Set the Names object.
+ * Set the /Names object.
* @param names the Names object
* @since PDF 1.2
*/
public void setNames(PDFNames names) {
- this.names = names;
+ put("Names", names.makeReference());
}
/**
+ * Returns the /Names object.
* @return the Names object if set, null otherwise.
* @since PDF 1.2
*/
public PDFNames getNames() {
- return this.names;
+ PDFReference ref = (PDFReference)get("Names");
+ return (ref != null ? (PDFNames)ref.getObject() : null);
}
/**
* @since PDF 1.4
*/
public void setMetadata(PDFMetadata meta) {
- this.metadata = meta;
+ if (getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
+ put("Metadata", meta.makeReference());
+ }
}
/**
- * @return the Metadata object if set, null otherwise.
+ * Returns the /Metadata object
+ * @return the /Metadata object if set, null otherwise.
* @since PDF 1.4
*/
public PDFMetadata getMetadata() {
- return this.metadata;
+ PDFReference ref = (PDFReference)get("Metadata");
+ return (ref != null ? (PDFMetadata)ref.getObject() : null);
}
/**
- * Adds an OutputIntent to the PDF
- * @param outputIntent the OutputIntent dictionary
+ * Returns the /OutputIntents array.
+ * @return the /OutputIntents array or null if it doesn't exist
+ * @since PDF 1.4
*/
- public void addOutputIntent(PDFOutputIntent outputIntent) {
- if (this.outputIntents == null) {
- this.outputIntents = new java.util.ArrayList();
- }
- this.outputIntents.add(outputIntent);
+ public PDFArray getOutputIntents() {
+ return (PDFArray)get("OutputIntents");
}
/**
- * {@inheritDoc}
- */
- public String toPDFString() {
- StringBuffer p = new StringBuffer(128);
- p.append(getObjectID());
- p.append("<< /Type /Catalog\n /Pages "
- + this.rootPages.referencePDF()
- + "\n");
- if (outline != null) {
- p.append(" /Outlines " + outline.referencePDF() + "\n");
- p.append(" /PageMode /UseOutlines\n");
- } else {
- switch (pageMode) {
- case PAGEMODE_USEOUTLINES:
- p.append(" /PageMode /UseOutlines\n");
- break;
- case PAGEMODE_USETHUMBS:
- p.append(" /PageMode /UseThumbs\n");
- break;
- case PAGEMODE_FULLSCREEN:
- p.append(" /PageMode /FullScreen\n");
- break;
- case PAGEMODE_USENONE:
- default:
- break;
- }
- }
- if (getDocumentSafely().hasDestinations() && getNames() != null) {
- p.append(" /Names " + getNames().referencePDF() + "\n");
- }
- if (getMetadata() != null
- && getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
- p.append(" /Metadata " + getMetadata().referencePDF() + "\n");
- }
- if (this.outputIntents != null
- && this.outputIntents.size() > 0
- && getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
- p.append(" /OutputIntents [");
- for (int i = 0, c = this.outputIntents.size(); i < c; i++) {
- PDFOutputIntent outputIntent = (PDFOutputIntent)this.outputIntents.get(i);
- if (i > 0) {
- p.append(" ");
- }
- p.append(outputIntent.referencePDF());
+ * Adds an OutputIntent to the PDF
+ * @param outputIntent the OutputIntent dictionary
+ * @since PDF 1.4
+ */
+ public void addOutputIntent(PDFOutputIntent outputIntent) {
+ if (getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
+ PDFArray outputIntents = getOutputIntents();
+ if (outputIntents == null) {
+ outputIntents = new PDFArray();
+ put("OutputIntents", outputIntents);
}
- p.append("]\n");
+ outputIntents.add(outputIntent);
}
- p.append(">>\nendobj\n");
- return p.toString();
}
-
+
}
import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.pdf.PDFConformanceException;
+import org.apache.fop.pdf.PDFDictionary;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFEncryptionManager;
import org.apache.fop.pdf.PDFEncryptionParams;
import org.apache.fop.pdf.PDFOutline;
import org.apache.fop.pdf.PDFOutputIntent;
import org.apache.fop.pdf.PDFPage;
+import org.apache.fop.pdf.PDFPageLabels;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFResources;
import org.apache.fop.pdf.PDFState;
page.getPageIndex());
pageReferences.put(page.getKey(), currentPage.referencePDF());
pvReferences.put(page.getKey(), page);
+
+ //Produce page labels
+ PDFPageLabels pageLabels = this.pdfDoc.getRoot().getPageLabels();
+ if (pageLabels == null) {
+ //Set up PageLabels
+ pageLabels = this.pdfDoc.getFactory().makePageLabels();
+ this.pdfDoc.getRoot().setPageLabels(pageLabels);
+ }
+ PDFDictionary dict = new PDFDictionary();
+ dict.put("P", page.getPageNumberString());
+ //TODO If the sequence of generated page numbers were inspected, this could be
+ //expressed in a more space-efficient way
+ pageLabels.getNums().put(page.getPageIndex(), dict);
}
/**
<changes>
<release version="FOP Trunk">
+ <action context="Code" dev="JM" type="add">
+ Added support for PDF page labels.
+ </action>
<action context="Code" dev="JM" type="add" fixes-bug="44176" due-to="Patrick Jaromin">
Added support for custom fonts in Java2DRenderer and derived renderers.
</action>