aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLuis Bernardo <lbernardo@apache.org>2012-10-17 23:36:43 +0000
committerLuis Bernardo <lbernardo@apache.org>2012-10-17 23:36:43 +0000
commit9772267c98b4996a889fb8bb2e8b628e2026dd09 (patch)
tree0facef43f7fa34ef360c6f298e00e5bf3092f081 /src
parent8d775d94555b992aa3986323c0867c2cc82c90e4 (diff)
downloadxmlgraphics-fop-9772267c98b4996a889fb8bb2e8b628e2026dd09.tar.gz
xmlgraphics-fop-9772267c98b4996a889fb8bb2e8b628e2026dd09.zip
bugzilla #54024: rewrote generation of /PageLabels dictionary
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1399483 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/java/org/apache/fop/pdf/PDFPageLabels.java174
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java7
2 files changed, 175 insertions, 6 deletions
diff --git a/src/java/org/apache/fop/pdf/PDFPageLabels.java b/src/java/org/apache/fop/pdf/PDFPageLabels.java
index 2c1a977b4..e95c97a25 100644
--- a/src/java/org/apache/fop/pdf/PDFPageLabels.java
+++ b/src/java/org/apache/fop/pdf/PDFPageLabels.java
@@ -19,11 +19,36 @@
package org.apache.fop.pdf;
+import java.util.regex.Pattern;
+
/**
* Class representing a PDF /PageLabels dictionary.
*/
public class PDFPageLabels extends PDFNumberTreeNode {
+ // TODO: maybe merge these constants with similar ones in PageNumberGenerator
+ private static final int DECIMAL = 1; // '0*1'
+ private static final int LOWER_ALPHA = 2; // 'a'
+ private static final int UPPER_ALPHA = 3; // 'A'
+ private static final int LOWER_ROMAN = 4; // 'i'
+ private static final int UPPER_ROMAN = 5; // 'I'
+ private static final int PREFIX = 6;
+
+ private static final PDFName S_D = new PDFName("D");
+ private static final PDFName S_UR = new PDFName("R");
+ private static final PDFName S_LR = new PDFName("r");
+ private static final PDFName S_UA = new PDFName("A");
+ private static final PDFName S_LA = new PDFName("a");
+
+ private static final Pattern MATCH_DECIMAL = Pattern.compile("\\d+");
+ private static final Pattern MATCH_ROMAN = Pattern.compile(
+ "^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$", Pattern.CASE_INSENSITIVE);
+ private static final Pattern MATCH_LETTER = Pattern.compile("^[a-zA-Z]$");
+
+ private int lastPageLabelType;
+ private int lastPageNumber;
+ private String lastZeroPaddingPrefix = "";
+
/**
* Create the /PageLabels dictionary
*/
@@ -45,4 +70,153 @@ public class PDFPageLabels extends PDFNumberTreeNode {
return nums;
}
+ /**
+ * Adds a new entry, if necessary, to the /PageLabels dictionary.
+ * @param index the page index (0 for page 1)
+ * @param pageLabel the page number as a string
+ */
+ public void addPageLabel(int index, String pageLabel) {
+ boolean addNewPageLabel = false;
+ String padding = "000000";
+ int currentPageNumber = 0;
+ int currentPageLabelType = 0;
+ String currentZeroPaddingPrefix = "";
+ if (MATCH_DECIMAL.matcher(pageLabel).matches()) {
+ // since an integer is the most common case we start with that
+ currentPageLabelType = DECIMAL;
+ currentPageNumber = Integer.parseInt(pageLabel);
+ int zeroPadding = 0;
+ if (pageLabel.startsWith("0")) {
+ while (pageLabel.charAt(zeroPadding) == '0') {
+ zeroPadding++;
+ }
+ currentZeroPaddingPrefix = padding.substring(0, zeroPadding);
+ if (currentZeroPaddingPrefix.length() != lastZeroPaddingPrefix.length()) {
+ addNewPageLabel = true;
+ }
+ } else {
+ if (lastZeroPaddingPrefix.length() != 0) {
+ addNewPageLabel = true;
+ }
+ }
+ } else if (MATCH_ROMAN.matcher(pageLabel).matches()) {
+ if (pageLabel.toLowerCase().equals(pageLabel)) {
+ currentPageLabelType = LOWER_ROMAN;
+ } else {
+ currentPageLabelType = UPPER_ROMAN;
+ }
+ currentPageNumber = romanToArabic(pageLabel);
+ } else if (MATCH_LETTER.matcher(pageLabel).matches()) {
+ if (pageLabel.toLowerCase().equals(pageLabel)) {
+ currentPageLabelType = LOWER_ALPHA;
+ } else {
+ currentPageLabelType = UPPER_ALPHA;
+ }
+ currentPageNumber = alphabeticToArabic(pageLabel);
+ } else {
+ // alphabetic numbering in XSL_FO and labelling in PDF are different after AA (AB versus BB)
+ // we will use the /P (prefix) label in that case
+ currentPageLabelType = PREFIX;
+ addNewPageLabel = true;
+ }
+ if (lastPageLabelType != currentPageLabelType) {
+ addNewPageLabel = true;
+ }
+ if (lastPageNumber != currentPageNumber - 1) {
+ addNewPageLabel = true;
+ }
+ if (addNewPageLabel) {
+ PDFNumsArray nums = getNums();
+ PDFDictionary dict = new PDFDictionary(nums);
+ PDFName pdfName = null;
+ switch (currentPageLabelType) {
+ case PREFIX:
+ dict.put("P", pageLabel);
+ break;
+ default:
+ switch (currentPageLabelType) {
+ case DECIMAL:
+ pdfName = S_D;
+ if (currentZeroPaddingPrefix.length() != 0) {
+ dict.put("P", currentZeroPaddingPrefix);
+ }
+ break;
+ case LOWER_ROMAN:
+ pdfName = S_LR;
+ break;
+ case UPPER_ROMAN:
+ pdfName = S_UR;
+ break;
+ case LOWER_ALPHA:
+ pdfName = S_LA;
+ break;
+ case UPPER_ALPHA:
+ pdfName = S_UA;
+ break;
+ default:
+ }
+ dict.put("S", pdfName);
+ if (currentPageNumber != 1) {
+ dict.put("St", currentPageNumber);
+ }
+ }
+ nums.put(index, dict);
+ }
+ lastPageLabelType = currentPageLabelType;
+ lastPageNumber = currentPageNumber;
+ lastZeroPaddingPrefix = currentZeroPaddingPrefix;
+ }
+
+ private int romanToArabic(String roman) {
+ int arabic = 0;
+ int previousValue = 0;
+ int newValue = 0;
+ String upperRoman = roman.toUpperCase();
+ for (int i = 0; i < upperRoman.length(); i++) {
+ char romanDigit = upperRoman.charAt(i);
+ switch (romanDigit) {
+ case 'I':
+ newValue = 1;
+ break;
+ case 'V':
+ newValue = 5;
+ break;
+ case 'X':
+ newValue = 10;
+ break;
+ case 'L':
+ newValue = 50;
+ break;
+ case 'C':
+ newValue = 100;
+ break;
+ case 'D':
+ newValue = 500;
+ break;
+ case 'M':
+ newValue = 1000;
+ break;
+ default:
+ }
+ if (previousValue < newValue) {
+ arabic -= previousValue;
+ } else {
+ arabic += previousValue;
+ }
+ previousValue = newValue;
+ }
+ arabic += previousValue;
+ return arabic;
+ }
+
+ private int alphabeticToArabic(String alpha) {
+ int arabic = 0;
+ if (alpha.length() > 1) {
+ // this should never happen
+ return arabic;
+ }
+ String lowerAlpha = alpha.toLowerCase();
+ arabic = (lowerAlpha.charAt(0) - 'a' + 1);
+ return arabic;
+ }
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
index fba9d922f..ef57c2152 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
@@ -308,12 +308,7 @@ class PDFRenderingUtil {
pageLabels = this.pdfDoc.getFactory().makePageLabels();
this.pdfDoc.getRoot().setPageLabels(pageLabels);
}
- PDFNumsArray nums = pageLabels.getNums();
- PDFDictionary dict = new PDFDictionary(nums);
- dict.put("P", pageNumber);
- //TODO If the sequence of generated page numbers were inspected, this could be
- //expressed in a more space-efficient way
- nums.put(pageIndex, dict);
+ pageLabels.addPageLabel(pageIndex, pageNumber);
}
/**