Save This Page
Home » iText-src-2.1.3 » com.lowagie » text » pdf » [javadoc | source]
    1   /*
    2    * Copyright 2003 by Paulo Soares.
    3    *
    4    * The contents of this file are subject to the Mozilla Public License Version 1.1
    5    * (the "License"); you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at http://www.mozilla.org/MPL/
    7    *
    8    * Software distributed under the License is distributed on an "AS IS" basis,
    9    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   10    * for the specific language governing rights and limitations under the License.
   11    *
   12    * The Original Code is 'iText, a free JAVA-PDF library'.
   13    *
   14    * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
   15    * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
   16    * All Rights Reserved.
   17    * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
   18    * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
   19    *
   20    * Contributor(s): all the names of the contributors are added in the source code
   21    * where applicable.
   22    *
   23    * Alternatively, the contents of this file may be used under the terms of the
   24    * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
   25    * provisions of LGPL are applicable instead of those above.  If you wish to
   26    * allow use of your version of this file only under the terms of the LGPL
   27    * License and not to allow others to use your version of this file under
   28    * the MPL, indicate your decision by deleting the provisions above and
   29    * replace them with the notice and other provisions required by the LGPL.
   30    * If you do not delete the provisions above, a recipient may use your version
   31    * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
   32    *
   33    * This library is free software; you can redistribute it and/or modify it
   34    * under the terms of the MPL as stated above or under the terms of the GNU
   35    * Library General Public License as published by the Free Software Foundation;
   36    * either version 2 of the License, or any later version.
   37    *
   38    * This library is distributed in the hope that it will be useful, but WITHOUT
   39    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   40    * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
   41    * details.
   42    *
   43    * If you didn't download this code from the following link, you should check if
   44    * you aren't using an obsolete version:
   45    * http://www.lowagie.com/iText/
   46    */
   47   
   48   package com.lowagie.text.pdf;
   49   
   50   import java.io.BufferedWriter;
   51   import java.io.IOException;
   52   import java.io.InputStream;
   53   import java.io.OutputStream;
   54   import java.io.OutputStreamWriter;
   55   import java.io.Reader;
   56   import java.io.Writer;
   57   import java.util.ArrayList;
   58   import java.util.HashMap;
   59   import java.util.Iterator;
   60   import java.util.List;
   61   import java.util.Map;
   62   import java.util.Stack;
   63   import java.util.StringTokenizer;
   64   
   65   import com.lowagie.text.xml.simpleparser.IanaEncodings;
   66   import com.lowagie.text.xml.simpleparser.SimpleXMLDocHandler;
   67   import com.lowagie.text.xml.simpleparser.SimpleXMLParser;
   68   /**
   69    * Bookmark processing in a simple way. It has some limitations, mainly the only
   70    * action types supported are GoTo, GoToR, URI and Launch.
   71    * <p>
   72    * The list structure is composed by a number of HashMap, keyed by strings, one HashMap
   73    * for each bookmark.
   74    * The element values are all strings with the exception of the key "Kids" that has
   75    * another list for the child bookmarks.
   76    * <p>
   77    * All the bookmarks have a "Title" with the
   78    * bookmark title and optionally a "Style" that can be "bold", "italic" or a
   79    * combination of both. They can also have a "Color" key with a value of three
   80    * floats separated by spaces. The key "Open" can have the values "true" or "false" and
   81    * signals the open status of the children. It's "true" by default.
   82    * <p>
   83    * The actions and the parameters can be:
   84    * <ul>
   85    * <li>"Action" = "GoTo" - "Page" | "Named"
   86    * <ul>
   87    * <li>"Page" = "3 XYZ 70 400 null" - page number followed by a destination (/XYZ is also accepted)
   88    * <li>"Named" = "named_destination"
   89    * </ul>
   90    * <li>"Action" = "GoToR" - "Page" | "Named" | "NamedN", "File", ["NewWindow"]
   91    * <ul>
   92    * <li>"Page" = "3 XYZ 70 400 null" - page number followed by a destination (/XYZ is also accepted)
   93    * <li>"Named" = "named_destination_as_a_string"
   94    * <li>"NamedN" = "named_destination_as_a_name"
   95    * <li>"File" - "the_file_to_open"
   96    * <li>"NewWindow" - "true" or "false"
   97    * </ul>
   98    * <li>"Action" = "URI" - "URI"
   99    * <ul>
  100    * <li>"URI" = "http://sf.net" - URI to jump to
  101    * </ul>
  102    * <li>"Action" = "Launch" - "File"
  103    * <ul>
  104    * <li>"File" - "the_file_to_open_or_execute"
  105    * </ul>
  106    * @author Paulo Soares (psoares@consiste.pt)
  107    */
  108   public final class SimpleBookmark implements SimpleXMLDocHandler {
  109       
  110       private ArrayList topList;
  111       private Stack attr = new Stack();
  112       
  113       /** Creates a new instance of SimpleBookmark */
  114       private SimpleBookmark() {
  115       }
  116       
  117       private static List bookmarkDepth(PdfReader reader, PdfDictionary outline, IntHashtable pages) {
  118           ArrayList list = new ArrayList();
  119           while (outline != null) {
  120               HashMap map = new HashMap();
  121               PdfString title = (PdfString)PdfReader.getPdfObjectRelease(outline.get(PdfName.TITLE));
  122               map.put("Title", title.toUnicodeString());
  123               PdfArray color = (PdfArray)PdfReader.getPdfObjectRelease(outline.get(PdfName.C));
  124               if (color != null && color.getArrayList().size() == 3) {
  125                   ByteBuffer out = new ByteBuffer();
  126                   ArrayList arr = color.getArrayList();
  127                   out.append(((PdfNumber)arr.get(0)).floatValue()).append(' ');
  128                   out.append(((PdfNumber)arr.get(1)).floatValue()).append(' ');
  129                   out.append(((PdfNumber)arr.get(2)).floatValue());
  130                   map.put("Color", PdfEncodings.convertToString(out.toByteArray(), null));
  131               }
  132               PdfNumber style = (PdfNumber)PdfReader.getPdfObjectRelease(outline.get(PdfName.F));
  133               if (style != null) {
  134                   int f = style.intValue();
  135                   String s = "";
  136                   if ((f & 1) != 0)
  137                       s += "italic ";
  138                   if ((f & 2) != 0)
  139                       s += "bold ";
  140                   s = s.trim();
  141                   if (s.length() != 0) 
  142                       map.put("Style", s);
  143               }
  144               PdfNumber count = (PdfNumber)PdfReader.getPdfObjectRelease(outline.get(PdfName.COUNT));
  145               if (count != null && count.intValue() < 0)
  146                   map.put("Open", "false");
  147               try {
  148                   PdfObject dest = PdfReader.getPdfObjectRelease(outline.get(PdfName.DEST));
  149                   if (dest != null) {
  150                       mapGotoBookmark(map, dest, pages); //changed by ujihara 2004-06-13
  151                   }
  152                   else {
  153                       PdfDictionary action = (PdfDictionary)PdfReader.getPdfObjectRelease(outline.get(PdfName.A));
  154                       if (action != null) {
  155                           if (PdfName.GOTO.equals(PdfReader.getPdfObjectRelease(action.get(PdfName.S)))) {
  156                               dest = PdfReader.getPdfObjectRelease(action.get(PdfName.D));
  157                               if (dest != null) {
  158                                   mapGotoBookmark(map, dest, pages);
  159                               }
  160                           }
  161                           else if (PdfName.URI.equals(PdfReader.getPdfObjectRelease(action.get(PdfName.S)))) {
  162                               map.put("Action", "URI");
  163                               map.put("URI", ((PdfString)PdfReader.getPdfObjectRelease(action.get(PdfName.URI))).toUnicodeString());
  164                           }
  165                           else if (PdfName.GOTOR.equals(PdfReader.getPdfObjectRelease(action.get(PdfName.S)))) {
  166                               dest = PdfReader.getPdfObjectRelease(action.get(PdfName.D));
  167                               if (dest != null) {
  168                                   if (dest.isString())
  169                                       map.put("Named", dest.toString());
  170                                   else if (dest.isName())
  171                                       map.put("NamedN", PdfName.decodeName(dest.toString()));
  172                                   else if (dest.isArray()) {
  173                                       ArrayList arr = ((PdfArray)dest).getArrayList();
  174                                       StringBuffer s = new StringBuffer();
  175                                       s.append(arr.get(0).toString());
  176                                       s.append(' ').append(arr.get(1).toString());
  177                                       for (int k = 2; k < arr.size(); ++k)
  178                                           s.append(' ').append(arr.get(k).toString());
  179                                       map.put("Page", s.toString());
  180                                   }
  181                               }
  182                               map.put("Action", "GoToR");
  183                               PdfObject file = PdfReader.getPdfObjectRelease(action.get(PdfName.F));
  184                               if (file != null) {
  185                                   if (file.isString())
  186                                       map.put("File", ((PdfString)file).toUnicodeString());
  187                                   else if (file.isDictionary()) {
  188                                       file = PdfReader.getPdfObject(((PdfDictionary)file).get(PdfName.F));
  189                                       if (file.isString())
  190                                           map.put("File", ((PdfString)file).toUnicodeString());
  191                                   }
  192                               }
  193                               PdfObject newWindow = PdfReader.getPdfObjectRelease(action.get(PdfName.NEWWINDOW));
  194                               if (newWindow != null)
  195                                   map.put("NewWindow", newWindow.toString());
  196                           }
  197                           else if (PdfName.LAUNCH.equals(PdfReader.getPdfObjectRelease(action.get(PdfName.S)))) {
  198                               map.put("Action", "Launch");
  199                               PdfObject file = PdfReader.getPdfObjectRelease(action.get(PdfName.F));
  200                               if (file == null)
  201                                   file = PdfReader.getPdfObjectRelease(action.get(PdfName.WIN));
  202                               if (file != null) {
  203                                   if (file.isString())
  204                                       map.put("File", ((PdfString)file).toUnicodeString());
  205                                   else if (file.isDictionary()) {
  206                                       file = PdfReader.getPdfObjectRelease(((PdfDictionary)file).get(PdfName.F));
  207                                       if (file.isString())
  208                                           map.put("File", ((PdfString)file).toUnicodeString());
  209                                   }
  210                               }
  211                           }
  212                       }
  213                   }
  214               }
  215               catch (Exception e) {
  216                   //empty on purpose
  217               }
  218               PdfDictionary first = (PdfDictionary)PdfReader.getPdfObjectRelease(outline.get(PdfName.FIRST));
  219               if (first != null) {
  220                   map.put("Kids", bookmarkDepth(reader, first, pages));
  221               }
  222               list.add(map);
  223               outline = (PdfDictionary)PdfReader.getPdfObjectRelease(outline.get(PdfName.NEXT));
  224           }
  225           return list;
  226       }
  227       
  228   	private static void mapGotoBookmark(HashMap map, PdfObject dest, IntHashtable pages) 
  229   	{
  230   		if (dest.isString())
  231   			map.put("Named", dest.toString());
  232   		else if (dest.isName())
  233   			map.put("Named", PdfName.decodeName(dest.toString()));
  234   		else if (dest.isArray()) 
  235   			map.put("Page", makeBookmarkParam((PdfArray)dest, pages)); //changed by ujihara 2004-06-13
  236   		map.put("Action", "GoTo");
  237   	}
  238   
  239   	private static String makeBookmarkParam(PdfArray dest, IntHashtable pages)
  240   	{
  241   		ArrayList arr = dest.getArrayList();
  242   		StringBuffer s = new StringBuffer();
  243           if (((PdfObject)arr.get(0)).isNumber())
  244               s.append(((PdfNumber)arr.get(0)).intValue() + 1);
  245           else
  246               s.append(pages.get(getNumber((PdfIndirectReference)arr.get(0)))); //changed by ujihara 2004-06-13
  247   		s.append(' ').append(arr.get(1).toString().substring(1));
  248   		for (int k = 2; k < arr.size(); ++k)
  249   			s.append(' ').append(arr.get(k).toString());
  250   		return s.toString();
  251   	}
  252   	
  253   	/**
  254   	 * Gets number of indirect. If type of directed indirect is PAGES, it refers PAGE object through KIDS.
  255   	 * (Contributed by Kazuya Ujihara)
  256   	 * @param indirect 
  257   	 * 2004-06-13
  258   	 */
  259   	private static int getNumber(PdfIndirectReference indirect)
  260   	{
  261   		PdfDictionary pdfObj = (PdfDictionary)PdfReader.getPdfObjectRelease(indirect);
  262   		if (pdfObj.contains(PdfName.TYPE) && pdfObj.get(PdfName.TYPE).equals(PdfName.PAGES) && pdfObj.contains(PdfName.KIDS)) 
  263   		{
  264   			PdfArray kids = (PdfArray)pdfObj.get(PdfName.KIDS);
  265   			indirect = (PdfIndirectReference)kids.arrayList.get(0);
  266   		}
  267   		return indirect.getNumber();
  268   	}
  269       
  270       /**
  271        * Gets a <CODE>List</CODE> with the bookmarks. It returns <CODE>null</CODE> if
  272        * the document doesn't have any bookmarks.
  273        * @param reader the document
  274        * @return a <CODE>List</CODE> with the bookmarks or <CODE>null</CODE> if the
  275        * document doesn't have any
  276        */    
  277       public static List getBookmark(PdfReader reader) {
  278           PdfDictionary catalog = reader.getCatalog();
  279           PdfObject obj = PdfReader.getPdfObjectRelease(catalog.get(PdfName.OUTLINES));
  280           if (obj == null || !obj.isDictionary())
  281               return null;
  282           PdfDictionary outlines = (PdfDictionary)obj;
  283           IntHashtable pages = new IntHashtable();
  284           int numPages = reader.getNumberOfPages();
  285           for (int k = 1; k <= numPages; ++k) {
  286               pages.put(reader.getPageOrigRef(k).getNumber(), k);
  287               reader.releasePage(k);
  288           }
  289           return bookmarkDepth(reader, (PdfDictionary)PdfReader.getPdfObjectRelease(outlines.get(PdfName.FIRST)), pages);
  290       }
  291       
  292       /**
  293        * Removes the bookmark entries for a number of page ranges. The page ranges
  294        * consists of a number of pairs with the start/end page range. The page numbers
  295        * are inclusive.
  296        * @param list the bookmarks
  297        * @param pageRange the page ranges, always in pairs.
  298        */    
  299       public static void eliminatePages(List list, int pageRange[]) {
  300           if (list == null)
  301               return;
  302           for (Iterator it = list.listIterator(); it.hasNext();) {
  303               HashMap map = (HashMap)it.next();
  304               boolean hit = false;
  305               if ("GoTo".equals(map.get("Action"))) {
  306                   String page = (String)map.get("Page");
  307                   if (page != null) {
  308                       page = page.trim();
  309                       int idx = page.indexOf(' ');
  310                       int pageNum;
  311                       if (idx < 0)
  312                           pageNum = Integer.parseInt(page);
  313                       else
  314                           pageNum = Integer.parseInt(page.substring(0, idx));
  315                       int len = pageRange.length & 0xfffffffe;
  316                       for (int k = 0; k < len; k += 2) {
  317                           if (pageNum >= pageRange[k] && pageNum <= pageRange[k + 1]) {
  318                               hit = true;
  319                               break;
  320                           }
  321                       }
  322                   }
  323               }
  324               List kids = (List)map.get("Kids");
  325               if (kids != null) {
  326                   eliminatePages(kids, pageRange);
  327                   if (kids.isEmpty()) {
  328                       map.remove("Kids");
  329                       kids = null;
  330                   }
  331               }
  332               if (hit) {
  333                   if (kids == null)
  334                       it.remove();
  335                   else {
  336                       map.remove("Action");
  337                       map.remove("Page");
  338                       map.remove("Named");
  339                   }
  340               }
  341           }
  342       }
  343       
  344       /**
  345        * For the pages in range add the <CODE>pageShift</CODE> to the page number.
  346        * The page ranges
  347        * consists of a number of pairs with the start/end page range. The page numbers
  348        * are inclusive.
  349        * @param list the bookmarks
  350        * @param pageShift the number to add to the pages in range
  351        * @param pageRange the page ranges, always in pairs. It can be <CODE>null</CODE>
  352        * to include all the pages
  353        */    
  354       public static void shiftPageNumbers(List list, int pageShift, int pageRange[]) {
  355           if (list == null)
  356               return;
  357           for (Iterator it = list.listIterator(); it.hasNext();) {
  358               HashMap map = (HashMap)it.next();
  359               if ("GoTo".equals(map.get("Action"))) {
  360                   String page = (String)map.get("Page");
  361                   if (page != null) {
  362                       page = page.trim();
  363                       int idx = page.indexOf(' ');
  364                       int pageNum;
  365                       if (idx < 0)
  366                           pageNum = Integer.parseInt(page);
  367                       else
  368                           pageNum = Integer.parseInt(page.substring(0, idx));
  369                       boolean hit = false;
  370                       if (pageRange == null)
  371                           hit = true;
  372                       else {
  373                           int len = pageRange.length & 0xfffffffe;
  374                           for (int k = 0; k < len; k += 2) {
  375                               if (pageNum >= pageRange[k] && pageNum <= pageRange[k + 1]) {
  376                                   hit = true;
  377                                   break;
  378                               }
  379                           }
  380                       }
  381                       if (hit) {
  382                           if (idx < 0)
  383                               page = Integer.toString(pageNum + pageShift);
  384                           else
  385                               page = (pageNum + pageShift) + page.substring(idx);
  386                       }
  387                       map.put("Page", page);
  388                   }
  389               }
  390               List kids = (List)map.get("Kids");
  391               if (kids != null)
  392                   shiftPageNumbers(kids, pageShift, pageRange);
  393           }
  394       }
  395       
  396       static void createOutlineAction(PdfDictionary outline, HashMap map, PdfWriter writer, boolean namedAsNames) {
  397           try {
  398               String action = (String)map.get("Action");
  399               if ("GoTo".equals(action)) {
  400                   String p;
  401                   if ((p = (String)map.get("Named")) != null) {
  402                       if (namedAsNames)
  403                           outline.put(PdfName.DEST, new PdfName(p));
  404                       else
  405                           outline.put(PdfName.DEST, new PdfString(p, null));
  406                   }
  407                   else if ((p = (String)map.get("Page")) != null) {
  408                       PdfArray ar = new PdfArray();
  409                       StringTokenizer tk = new StringTokenizer(p);
  410                       int n = Integer.parseInt(tk.nextToken());
  411                       ar.add(writer.getPageReference(n));
  412                       if (!tk.hasMoreTokens()) {
  413                           ar.add(PdfName.XYZ);
  414                           ar.add(new float[]{0, 10000, 0});
  415                       }
  416                       else {
  417                           String fn = tk.nextToken();
  418                           if (fn.startsWith("/"))
  419                               fn = fn.substring(1);
  420                           ar.add(new PdfName(fn));
  421                           for (int k = 0; k < 4 && tk.hasMoreTokens(); ++k) {
  422                               fn = tk.nextToken();
  423                               if (fn.equals("null"))
  424                                   ar.add(PdfNull.PDFNULL);
  425                               else
  426                                   ar.add(new PdfNumber(fn));
  427                           }
  428                       }
  429                       outline.put(PdfName.DEST, ar);
  430                   }
  431               }
  432               else if ("GoToR".equals(action)) {
  433                   String p;
  434                   PdfDictionary dic = new PdfDictionary();
  435                   if ((p = (String)map.get("Named")) != null)
  436                       dic.put(PdfName.D, new PdfString(p, null));
  437                   else if ((p = (String)map.get("NamedN")) != null)
  438                       dic.put(PdfName.D, new PdfName(p));
  439                   else if ((p = (String)map.get("Page")) != null){
  440                       PdfArray ar = new PdfArray();
  441                       StringTokenizer tk = new StringTokenizer(p);
  442                       ar.add(new PdfNumber(tk.nextToken()));
  443                       if (!tk.hasMoreTokens()) {
  444                           ar.add(PdfName.XYZ);
  445                           ar.add(new float[]{0, 10000, 0});
  446                       }
  447                       else {
  448                           String fn = tk.nextToken();
  449                           if (fn.startsWith("/"))
  450                               fn = fn.substring(1);
  451                           ar.add(new PdfName(fn));
  452                           for (int k = 0; k < 4 && tk.hasMoreTokens(); ++k) {
  453                               fn = tk.nextToken();
  454                               if (fn.equals("null"))
  455                                   ar.add(PdfNull.PDFNULL);
  456                               else
  457                                   ar.add(new PdfNumber(fn));
  458                           }
  459                       }
  460                       dic.put(PdfName.D, ar);
  461                   }
  462                   String file = (String)map.get("File");
  463                   if (dic.size() > 0 && file != null) {
  464                       dic.put(PdfName.S,  PdfName.GOTOR);
  465                       dic.put(PdfName.F, new PdfString(file));
  466                       String nw = (String)map.get("NewWindow");
  467                       if (nw != null) {
  468                           if (nw.equals("true"))
  469                               dic.put(PdfName.NEWWINDOW, PdfBoolean.PDFTRUE);
  470                           else if (nw.equals("false"))
  471                               dic.put(PdfName.NEWWINDOW, PdfBoolean.PDFFALSE);
  472                       }
  473                       outline.put(PdfName.A, dic);
  474                   }
  475               }
  476               else if ("URI".equals(action)) {
  477                   String uri = (String)map.get("URI");
  478                   if (uri != null) {
  479                       PdfDictionary dic = new PdfDictionary();
  480                       dic.put(PdfName.S, PdfName.URI);
  481                       dic.put(PdfName.URI, new PdfString(uri));
  482                       outline.put(PdfName.A, dic);
  483                   }
  484               }
  485               else if ("Launch".equals(action)) {
  486                   String file = (String)map.get("File");
  487                   if (file != null) {
  488                       PdfDictionary dic = new PdfDictionary();
  489                       dic.put(PdfName.S, PdfName.LAUNCH);
  490                       dic.put(PdfName.F, new PdfString(file));
  491                       outline.put(PdfName.A, dic);
  492                   }
  493               }
  494           }
  495           catch (Exception e) {
  496               // empty on purpose
  497           }
  498       }
  499   
  500       public static Object[] iterateOutlines(PdfWriter writer, PdfIndirectReference parent, List kids, boolean namedAsNames) throws IOException {
  501           PdfIndirectReference refs[] = new PdfIndirectReference[kids.size()];
  502           for (int k = 0; k < refs.length; ++k)
  503               refs[k] = writer.getPdfIndirectReference();
  504           int ptr = 0;
  505           int count = 0;
  506           for (Iterator it = kids.listIterator(); it.hasNext(); ++ptr) {
  507               HashMap map = (HashMap)it.next();
  508               Object lower[] = null;
  509               List subKid = (List)map.get("Kids");
  510               if (subKid != null && !subKid.isEmpty())
  511                   lower = iterateOutlines(writer, refs[ptr], subKid, namedAsNames);
  512               PdfDictionary outline = new PdfDictionary();
  513               ++count;
  514               if (lower != null) {
  515                   outline.put(PdfName.FIRST, (PdfIndirectReference)lower[0]);
  516                   outline.put(PdfName.LAST, (PdfIndirectReference)lower[1]);
  517                   int n = ((Integer)lower[2]).intValue();
  518                   if ("false".equals(map.get("Open"))) {
  519                       outline.put(PdfName.COUNT, new PdfNumber(-n));
  520                   }
  521                   else {
  522                       outline.put(PdfName.COUNT, new PdfNumber(n));
  523                       count += n;
  524                   }
  525               }
  526               outline.put(PdfName.PARENT, parent);
  527               if (ptr > 0)
  528                   outline.put(PdfName.PREV, refs[ptr - 1]);
  529               if (ptr < refs.length - 1)
  530                   outline.put(PdfName.NEXT, refs[ptr + 1]);
  531               outline.put(PdfName.TITLE, new PdfString((String)map.get("Title"), PdfObject.TEXT_UNICODE));
  532               String color = (String)map.get("Color");
  533               if (color != null) {
  534                   try {
  535                       PdfArray arr = new PdfArray();
  536                       StringTokenizer tk = new StringTokenizer(color);
  537                       for (int k = 0; k < 3; ++k) {
  538                           float f = Float.parseFloat(tk.nextToken());
  539                           if (f < 0) f = 0;
  540                           if (f > 1) f = 1;
  541                           arr.add(new PdfNumber(f));
  542                       }
  543                       outline.put(PdfName.C, arr);
  544                   } catch(Exception e){} //in case it's malformed
  545               }
  546               String style = (String)map.get("Style");
  547               if (style != null) {
  548                   style = style.toLowerCase();
  549                   int bits = 0;
  550                   if (style.indexOf("italic") >= 0)
  551                       bits |= 1;
  552                   if (style.indexOf("bold") >= 0)
  553                       bits |= 2;
  554                   if (bits != 0)
  555                       outline.put(PdfName.F, new PdfNumber(bits));
  556               }
  557               createOutlineAction(outline, map, writer, namedAsNames);
  558               writer.addToBody(outline, refs[ptr]);
  559           }
  560           return new Object[]{refs[0], refs[refs.length - 1], new Integer(count)};
  561       }
  562       
  563       /**
  564        * Exports the bookmarks to XML. Only of use if the generation is to be include in
  565        * some other XML document.
  566        * @param list the bookmarks
  567        * @param out the export destination. The writer is not closed
  568        * @param indent the indentation level. Pretty printing significant only
  569        * @param onlyASCII codes above 127 will always be escaped with &amp;#nn; if <CODE>true</CODE>,
  570        * whatever the encoding
  571        * @throws IOException on error
  572        */
  573       public static void exportToXMLNode(List list, Writer out, int indent, boolean onlyASCII) throws IOException {
  574           String dep = "";
  575           for (int k = 0; k < indent; ++k)
  576               dep += "  ";
  577           for (Iterator it = list.iterator(); it.hasNext();) {
  578               HashMap map = (HashMap)it.next();
  579               String title = null;
  580               out.write(dep);
  581               out.write("<Title ");
  582               List kids = null;
  583               for (Iterator e = map.entrySet().iterator(); e.hasNext();) {
  584                   Map.Entry entry = (Map.Entry) e.next();
  585                   String key = (String) entry.getKey();
  586                   if (key.equals("Title")) {
  587                       title = (String) entry.getValue();
  588                       continue;
  589                   }
  590                   else if (key.equals("Kids")) {
  591                       kids = (List) entry.getValue();
  592                       continue;
  593                   }
  594                   else {
  595                       out.write(key);
  596                       out.write("=\"");
  597                       String value = (String) entry.getValue();
  598                       if (key.equals("Named") || key.equals("NamedN"))
  599                           value = SimpleNamedDestination.escapeBinaryString(value);
  600                       out.write(SimpleXMLParser.escapeXML(value, onlyASCII));
  601                       out.write("\" ");
  602                   }
  603               }
  604               out.write(">");
  605               if (title == null)
  606                   title = "";
  607               out.write(SimpleXMLParser.escapeXML(title, onlyASCII));
  608               if (kids != null) {
  609                   out.write("\n");
  610                   exportToXMLNode(kids, out, indent + 1, onlyASCII);
  611                   out.write(dep);
  612               }
  613               out.write("</Title>\n");
  614           }
  615       }
  616       
  617       /**
  618        * Exports the bookmarks to XML. The DTD for this XML is:
  619        * <p>
  620        * <pre>
  621        * &lt;?xml version='1.0' encoding='UTF-8'?&gt;
  622        * &lt;!ELEMENT Title (#PCDATA|Title)*&gt;
  623        * &lt;!ATTLIST Title
  624        *    Action CDATA #IMPLIED
  625        *    Open CDATA #IMPLIED
  626        *    Page CDATA #IMPLIED
  627        *    URI CDATA #IMPLIED
  628        *    File CDATA #IMPLIED
  629        *    Named CDATA #IMPLIED
  630        *    NamedN CDATA #IMPLIED
  631        *    NewWindow CDATA #IMPLIED
  632        *    Style CDATA #IMPLIED
  633        *    Color CDATA #IMPLIED
  634        * &gt;
  635        * &lt;!ELEMENT Bookmark (Title)*&gt;
  636        * </pre>
  637        * @param list the bookmarks
  638        * @param out the export destination. The stream is not closed
  639        * @param encoding the encoding according to IANA conventions
  640        * @param onlyASCII codes above 127 will always be escaped with &amp;#nn; if <CODE>true</CODE>,
  641        * whatever the encoding
  642        * @throws IOException on error
  643        */    
  644       public static void exportToXML(List list, OutputStream out, String encoding, boolean onlyASCII) throws IOException {
  645           String jenc = IanaEncodings.getJavaEncoding(encoding);
  646           Writer wrt = new BufferedWriter(new OutputStreamWriter(out, jenc));
  647           exportToXML(list, wrt, encoding, onlyASCII);
  648       }
  649       
  650       /**
  651        * Exports the bookmarks to XML.
  652        * @param list the bookmarks
  653        * @param wrt the export destination. The writer is not closed
  654        * @param encoding the encoding according to IANA conventions
  655        * @param onlyASCII codes above 127 will always be escaped with &amp;#nn; if <CODE>true</CODE>,
  656        * whatever the encoding
  657        * @throws IOException on error
  658        */
  659       public static void exportToXML(List list, Writer wrt, String encoding, boolean onlyASCII) throws IOException {
  660           wrt.write("<?xml version=\"1.0\" encoding=\"");
  661           wrt.write(SimpleXMLParser.escapeXML(encoding, onlyASCII));
  662           wrt.write("\"?>\n<Bookmark>\n");
  663           exportToXMLNode(list, wrt, 1, onlyASCII);
  664           wrt.write("</Bookmark>\n");
  665           wrt.flush();
  666       }
  667       
  668       /**
  669        * Import the bookmarks from XML.
  670        * @param in the XML source. The stream is not closed
  671        * @throws IOException on error
  672        * @return the bookmarks
  673        */    
  674       public static List importFromXML(InputStream in) throws IOException {
  675           SimpleBookmark book = new SimpleBookmark();
  676           SimpleXMLParser.parse(book, in);
  677           return book.topList;
  678       }
  679       
  680       /**
  681        * Import the bookmarks from XML.
  682        * @param in the XML source. The reader is not closed
  683        * @throws IOException on error
  684        * @return the bookmarks
  685        */
  686       public static List importFromXML(Reader in) throws IOException {
  687           SimpleBookmark book = new SimpleBookmark();
  688           SimpleXMLParser.parse(book, in);
  689           return book.topList;
  690       }
  691       
  692       public void endDocument() {
  693       }
  694       
  695       public void endElement(String tag) {
  696           if (tag.equals("Bookmark")) {
  697               if (attr.isEmpty())
  698                   return;
  699               else
  700                   throw new RuntimeException("Bookmark end tag out of place.");
  701           }
  702           if (!tag.equals("Title"))
  703               throw new RuntimeException("Invalid end tag - " + tag);
  704           HashMap attributes = (HashMap)attr.pop();
  705           String title = (String)attributes.get("Title");
  706           attributes.put("Title",  title.trim());
  707           String named = (String)attributes.get("Named");
  708           if (named != null)
  709               attributes.put("Named", SimpleNamedDestination.unEscapeBinaryString(named));
  710           named = (String)attributes.get("NamedN");
  711           if (named != null)
  712               attributes.put("NamedN", SimpleNamedDestination.unEscapeBinaryString(named));
  713           if (attr.isEmpty())
  714               topList.add(attributes);
  715           else {
  716               HashMap parent = (HashMap)attr.peek();
  717               List kids = (List)parent.get("Kids");
  718               if (kids == null) {
  719                   kids = new ArrayList();
  720                   parent.put("Kids", kids);
  721               }
  722               kids.add(attributes);
  723           }
  724       }
  725       
  726       public void startDocument() {
  727       }
  728       
  729       public void startElement(String tag, HashMap h) {
  730           if (topList == null) {
  731               if (tag.equals("Bookmark")) {
  732                   topList = new ArrayList();
  733                   return;
  734               }
  735               else
  736                   throw new RuntimeException("Root element is not Bookmark: " + tag);
  737           }
  738           if (!tag.equals("Title"))
  739               throw new RuntimeException("Tag " + tag + " not allowed.");
  740           HashMap attributes = new HashMap(h);
  741           attributes.put("Title", "");
  742           attributes.remove("Kids");
  743           attr.push(attributes);
  744       }
  745       
  746       public void text(String str) {
  747           if (attr.isEmpty())
  748               return;
  749           HashMap attributes = (HashMap)attr.peek();
  750           String title = (String)attributes.get("Title");
  751           title += str;
  752           attributes.put("Title", title);
  753       }    
  754   }

Save This Page
Home » iText-src-2.1.3 » com.lowagie » text » pdf » [javadoc | source]