diff options
author | Luis Bernardo <lbernardo@apache.org> | 2012-10-17 23:36:43 +0000 |
---|---|---|
committer | Luis Bernardo <lbernardo@apache.org> | 2012-10-17 23:36:43 +0000 |
commit | 9772267c98b4996a889fb8bb2e8b628e2026dd09 (patch) | |
tree | 0facef43f7fa34ef360c6f298e00e5bf3092f081 /src | |
parent | 8d775d94555b992aa3986323c0867c2cc82c90e4 (diff) | |
download | xmlgraphics-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.java | 174 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java | 7 |
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); } /** |