001: /*
002: * $Id: PdfPageLabels.java 2890 2007-08-17 18:44:04Z psoares33 $
003: * $Name$
004: *
005: * Copyright 2001, 2002 Paulo Soares
006: *
007: * The contents of this file are subject to the Mozilla Public License Version 1.1
008: * (the "License"); you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the License.
014: *
015: * The Original Code is 'iText, a free JAVA-PDF library'.
016: *
017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
018: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
019: * All Rights Reserved.
020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
021: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
022: *
023: * Contributor(s): all the names of the contributors are added in the source code
024: * where applicable.
025: *
026: * Alternatively, the contents of this file may be used under the terms of the
027: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
028: * provisions of LGPL are applicable instead of those above. If you wish to
029: * allow use of your version of this file only under the terms of the LGPL
030: * License and not to allow others to use your version of this file under
031: * the MPL, indicate your decision by deleting the provisions above and
032: * replace them with the notice and other provisions required by the LGPL.
033: * If you do not delete the provisions above, a recipient may use your version
034: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
035: *
036: * This library is free software; you can redistribute it and/or modify it
037: * under the terms of the MPL as stated above or under the terms of the GNU
038: * Library General Public License as published by the Free Software Foundation;
039: * either version 2 of the License, or any later version.
040: *
041: * This library is distributed in the hope that it will be useful, but WITHOUT
042: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
043: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
044: * details.
045: *
046: * If you didn't download this code from the following link, you should check if
047: * you aren't using an obsolete version:
048: * http://www.lowagie.com/iText/
049: */
050:
051: package com.lowagie.text.pdf;
052:
053: import com.lowagie.text.ExceptionConverter;
054: import java.io.IOException;
055: import java.util.HashMap;
056:
057: import com.lowagie.text.factories.RomanAlphabetFactory;
058: import com.lowagie.text.factories.RomanNumberFactory;
059: import java.util.Arrays;
060:
061: /** Page labels are used to identify each
062: * page visually on the screen or in print.
063: * @author Paulo Soares (psoares@consiste.pt)
064: */
065: public class PdfPageLabels {
066:
067: /** Logical pages will have the form 1,2,3,...
068: */
069: public static final int DECIMAL_ARABIC_NUMERALS = 0;
070: /** Logical pages will have the form I,II,III,IV,...
071: */
072: public static final int UPPERCASE_ROMAN_NUMERALS = 1;
073: /** Logical pages will have the form i,ii,iii,iv,...
074: */
075: public static final int LOWERCASE_ROMAN_NUMERALS = 2;
076: /** Logical pages will have the form of uppercase letters
077: * (A to Z for the first 26 pages, AA to ZZ for the next 26, and so on)
078: */
079: public static final int UPPERCASE_LETTERS = 3;
080: /** Logical pages will have the form of uppercase letters
081: * (a to z for the first 26 pages, aa to zz for the next 26, and so on)
082: */
083: public static final int LOWERCASE_LETTERS = 4;
084: /** No logical page numbers are generated but fixed text may
085: * still exist
086: */
087: public static final int EMPTY = 5;
088: /** Dictionary values to set the logical page styles
089: */
090: static PdfName numberingStyle[] = new PdfName[] { PdfName.D,
091: PdfName.R, new PdfName("r"), PdfName.A, new PdfName("a") };
092: /** The sequence of logical pages. Will contain at least a value for page 1
093: */
094: private HashMap map;
095:
096: /** Creates a new PdfPageLabel with a default logical page 1
097: */
098: public PdfPageLabels() {
099: map = new HashMap();
100: addPageLabel(1, DECIMAL_ARABIC_NUMERALS, null, 1);
101: }
102:
103: /** Adds or replaces a page label.
104: * @param page the real page to start the numbering. First page is 1
105: * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS
106: * @param text the text to prefix the number. Can be <CODE>null</CODE> or empty
107: * @param firstPage the first logical page number
108: */
109: public void addPageLabel(int page, int numberStyle, String text,
110: int firstPage) {
111: if (page < 1 || firstPage < 1)
112: throw new IllegalArgumentException(
113: "In a page label the page numbers must be greater or equal to 1.");
114: PdfDictionary dic = new PdfDictionary();
115: if (numberStyle >= 0 && numberStyle < numberingStyle.length)
116: dic.put(PdfName.S, numberingStyle[numberStyle]);
117: if (text != null)
118: dic.put(PdfName.P, new PdfString(text,
119: PdfObject.TEXT_UNICODE));
120: if (firstPage != 1)
121: dic.put(PdfName.ST, new PdfNumber(firstPage));
122: map.put(new Integer(page - 1), dic);
123: }
124:
125: /** Adds or replaces a page label. The first logical page has the default
126: * of 1.
127: * @param page the real page to start the numbering. First page is 1
128: * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS
129: * @param text the text to prefix the number. Can be <CODE>null</CODE> or empty
130: */
131: public void addPageLabel(int page, int numberStyle, String text) {
132: addPageLabel(page, numberStyle, text, 1);
133: }
134:
135: /** Adds or replaces a page label. There is no text prefix and the first
136: * logical page has the default of 1.
137: * @param page the real page to start the numbering. First page is 1
138: * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS
139: */
140: public void addPageLabel(int page, int numberStyle) {
141: addPageLabel(page, numberStyle, null, 1);
142: }
143:
144: /** Adds or replaces a page label.
145: */
146: public void addPageLabel(PdfPageLabelFormat format) {
147: addPageLabel(format.physicalPage, format.numberStyle,
148: format.prefix, format.logicalPage);
149: }
150:
151: /** Removes a page label. The first page label can not be removed, only changed.
152: * @param page the real page to remove
153: */
154: public void removePageLabel(int page) {
155: if (page <= 1)
156: return;
157: map.remove(new Integer(page - 1));
158: }
159:
160: /** Gets the page label dictionary to insert into the document.
161: * @return the page label dictionary
162: */
163: PdfDictionary getDictionary(PdfWriter writer) {
164: try {
165: return PdfNumberTree.writeTree(map, writer);
166: } catch (IOException e) {
167: throw new ExceptionConverter(e);
168: }
169: }
170:
171: /**
172: * Retrieves the page labels from a PDF as an array of String objects.
173: * @param reader a PdfReader object that has the page labels you want to retrieve
174: * @return a String array or <code>null</code> if no page labels are present
175: */
176: public static String[] getPageLabels(PdfReader reader) {
177:
178: int n = reader.getNumberOfPages();
179:
180: PdfDictionary dict = reader.getCatalog();
181: PdfDictionary labels = (PdfDictionary) PdfReader
182: .getPdfObjectRelease(dict.get(PdfName.PAGELABELS));
183: if (labels == null)
184: return null;
185:
186: String[] labelstrings = new String[n];
187:
188: HashMap numberTree = PdfNumberTree.readTree(labels);
189:
190: int pagecount = 1;
191: Integer current;
192: String prefix = "";
193: char type = 'D';
194: for (int i = 0; i < n; i++) {
195: current = new Integer(i);
196: if (numberTree.containsKey(current)) {
197: PdfDictionary d = (PdfDictionary) PdfReader
198: .getPdfObjectRelease((PdfObject) numberTree
199: .get(current));
200: if (d.contains(PdfName.ST)) {
201: pagecount = ((PdfNumber) d.get(PdfName.ST))
202: .intValue();
203: } else {
204: pagecount = 1;
205: }
206: if (d.contains(PdfName.P)) {
207: prefix = ((PdfString) d.get(PdfName.P))
208: .toUnicodeString();
209: }
210: if (d.contains(PdfName.S)) {
211: type = ((PdfName) d.get(PdfName.S)).toString()
212: .charAt(1);
213: }
214: }
215: switch (type) {
216: default:
217: labelstrings[i] = prefix + pagecount;
218: break;
219: case 'R':
220: labelstrings[i] = prefix
221: + RomanNumberFactory
222: .getUpperCaseString(pagecount);
223: break;
224: case 'r':
225: labelstrings[i] = prefix
226: + RomanNumberFactory
227: .getLowerCaseString(pagecount);
228: break;
229: case 'A':
230: labelstrings[i] = prefix
231: + RomanAlphabetFactory
232: .getUpperCaseString(pagecount);
233: break;
234: case 'a':
235: labelstrings[i] = prefix
236: + RomanAlphabetFactory
237: .getLowerCaseString(pagecount);
238: break;
239: }
240: pagecount++;
241: }
242: return labelstrings;
243: }
244:
245: /**
246: * Retrieves the page labels from a PDF as an array of {@link PdfPageLabelFormat} objects.
247: * @param reader a PdfReader object that has the page labels you want to retrieve
248: * @return a PdfPageLabelEntry array, containing an entry for each format change
249: * or <code>null</code> if no page labels are present
250: */
251: public static PdfPageLabelFormat[] getPageLabelFormats(
252: PdfReader reader) {
253: PdfDictionary dict = reader.getCatalog();
254: PdfDictionary labels = (PdfDictionary) PdfReader
255: .getPdfObjectRelease(dict.get(PdfName.PAGELABELS));
256: if (labels == null)
257: return null;
258: HashMap numberTree = PdfNumberTree.readTree(labels);
259: Integer numbers[] = new Integer[numberTree.size()];
260: numbers = (Integer[]) numberTree.keySet().toArray(numbers);
261: Arrays.sort(numbers);
262: PdfPageLabelFormat[] formats = new PdfPageLabelFormat[numberTree
263: .size()];
264: String prefix;
265: int numberStyle;
266: int pagecount;
267: for (int k = 0; k < numbers.length; ++k) {
268: Integer key = numbers[k];
269: PdfDictionary d = (PdfDictionary) PdfReader
270: .getPdfObjectRelease((PdfObject) numberTree
271: .get(key));
272: if (d.contains(PdfName.ST)) {
273: pagecount = ((PdfNumber) d.get(PdfName.ST)).intValue();
274: } else {
275: pagecount = 1;
276: }
277: if (d.contains(PdfName.P)) {
278: prefix = ((PdfString) d.get(PdfName.P))
279: .toUnicodeString();
280: } else {
281: prefix = "";
282: }
283: if (d.contains(PdfName.S)) {
284: char type = ((PdfName) d.get(PdfName.S)).toString()
285: .charAt(1);
286: switch (type) {
287: case 'R':
288: numberStyle = UPPERCASE_ROMAN_NUMERALS;
289: break;
290: case 'r':
291: numberStyle = LOWERCASE_ROMAN_NUMERALS;
292: break;
293: case 'A':
294: numberStyle = UPPERCASE_LETTERS;
295: break;
296: case 'a':
297: numberStyle = LOWERCASE_LETTERS;
298: break;
299: default:
300: numberStyle = DECIMAL_ARABIC_NUMERALS;
301: break;
302: }
303: } else {
304: numberStyle = EMPTY;
305: }
306: formats[k] = new PdfPageLabelFormat(key.intValue() + 1,
307: numberStyle, prefix, pagecount);
308: }
309: return formats;
310: }
311:
312: public static class PdfPageLabelFormat {
313:
314: public int physicalPage;
315: public int numberStyle;
316: public String prefix;
317: public int logicalPage;
318:
319: /** Creates a page label format.
320: * @param physicalPage the real page to start the numbering. First page is 1
321: * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS
322: * @param prefix the text to prefix the number. Can be <CODE>null</CODE> or empty
323: * @param logicalPage the first logical page number
324: */
325: public PdfPageLabelFormat(int physicalPage, int numberStyle,
326: String prefix, int logicalPage) {
327: this.physicalPage = physicalPage;
328: this.numberStyle = numberStyle;
329: this.prefix = prefix;
330: this.logicalPage = logicalPage;
331: }
332: }
333: }
|