/* * $Id: PDFDocument.java,v 1.4 2007/09/22 12:58:40 gil1 Exp $ * * $Date: 2007/09/22 12:58:40 $ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package gnu.jpdf; import java.io.IOException; import java.io.OutputStream; import java.io.Serializable; import java.util.Vector; /** * <p>This class is the base of the PDF generator. A PDFDocument class is * created for a document, and each page, object, annotation, * etc is added to the document. * Once complete, the document can be written to an OutputStream, and the PDF * document's internal structures are kept in sync.</p> * * <p>Note that most programmers using this package will NEVER access * one of these objects directly. Most everything can be done using * <code>PDFJob</code> and <code>PDFGraphics</code>, so you don't need * to directly instantiate a <code>PDFDocument</code></p> * * <p>ezb - 20011115 - Wondering if the constructors should even be public. * When would someone want to make one of these and manipulate it outside * the context of a job and graphics object?</p> * * @author Peter T Mount, http://www.retep.org.uk/pdf/ * @author Eric Z. Beard, ericzbeard@hotmail.com * @author Gilbert DeLeeuw, gil1@users.sourceforge.net * @version $Revision: 1.4 $, $Date: 2007/09/22 12:58:40 $ */ public class PDFDocument implements Serializable { /* * NOTE: This class originated in uk.org.retep.pdf, by Peter T. Mount, and it * has been modified by Eric Z. Beard, ericzbeard@hotmail.com. The * package name was changed to gnu.jpdf and several inner classes were * moved out into their own files. */ /** * This is used to allocate objects a unique serial number in the document. */ protected int objser; /** * This vector contains each indirect object within the document. */ protected Vector<PDFObject> objects; /** * This is the Catalog object, which is required by each PDF Document */ private PDFCatalog catalog; /** * This is the info object. Although this is an optional object, we * include it. */ private PDFInfo info; /** * This is the Pages object, which is required by each PDF Document */ private PDFPageList pdfPageList; /** * This is the Outline object, which is optional */ private PDFOutline outline; /** * This holds a PDFObject describing the default border for annotations. * It's only used when the document is being written. */ protected PDFObject defaultOutlineBorder; /** * <p>This page mode indicates that the document * should be opened just with the page visible. This is the default</p> */ public static final int USENONE = 0; /** * <p>This page mode indicates that the Outlines * should also be displayed when the document is opened.</p> */ public static final int USEOUTLINES = 1; /** * <p>This page mode indicates that the Thumbnails should be visible when the * document first opens.</p> */ public static final int USETHUMBS = 2; /** * <p> * This page mode indicates that when the document is opened, it is displayed * in full-screen-mode. There is no menu bar, window controls nor any other * window present.</p> */ public static final int FULLSCREEN = 3; /** * <p> * These map the page modes just defined to the pagemodes setting of PDF. * </p> */ public static final String PDF_PAGE_MODES[] = { "/UseNone", "/UseOutlines", "/UseThumbs", "/FullScreen" }; /** * This is used to provide a unique name for a font */ private int fontid = 0; /** * <p>This is used to provide a unique name for an image</p> */ private int imageid = 0; /** * This holds the current fonts */ private Vector<PDFFont> fonts; /** * <p>This creates a PDF document with the default pagemode</p> */ public PDFDocument() { this(USENONE); } /** * <p>This creates a PDF document</p> * @param pagemode an int, determines how the document will present itself to * the viewer when it first opens. */ public PDFDocument(int pagemode) { objser = 1; objects = new Vector<PDFObject>(); fonts = new Vector<PDFFont>(); // Now create some standard objects add(pdfPageList = new PDFPageList()); add(catalog = new PDFCatalog(pdfPageList,pagemode)); add(info = new PDFInfo()); // Acroread on linux seems to die if there is no root outline add(getOutline()); } /** * This adds a top level object to the document. * * <p>Once added, it is allocated a unique serial number. * * <p><b>Note:</b> Not all object are added directly using this method. * Some objects which have Kids (in PDF sub-objects or children are * called Kids) will have their own add() method, which will call this * one internally. * * @param obj The PDFObject to add to the document * @return the unique serial number for this object. */ public synchronized int add(PDFObject obj) { objects.addElement(obj); obj.objser=objser++; // create a new serial number obj.pdfDocument = this; // so they can find the document they belong to // If its a page, then add it to the pages collection if(obj instanceof PDFPage) pdfPageList.add((PDFPage)obj); return obj.objser; } /** * <p>This returns a specific page. It's used mainly when using a * Serialized template file.</p> * * ?? How does a serialized template file work ??? * * @param page page number to return * @return PDFPage at that position */ public PDFPage getPage(int page) { return pdfPageList.getPage(page); } /** * @return the root outline */ public PDFOutline getOutline() { if(outline==null) { outline = new PDFOutline(); catalog.setOutline(outline); } return outline; } /** * This returns a font of the specified type and font. If the font has * not been defined, it creates a new font in the PDF document, and * returns it. * * @param type PDF Font Type - usually "/Type1" * @param font Java font name * @param style java.awt.Font style (NORMAL, BOLD etc) * @return PDFFont defining this font */ public PDFFont getFont(String type,String font,int style) { for(PDFFont ft : fonts) { if(ft.equals(type,font,style)) return ft; } // the font wasn't found, so create it fontid++; PDFFont ft = new PDFFont("/F"+fontid,type,font,style); add(ft); fonts.addElement(ft); return ft; } /** * Sets a unique name to a PDFImage * @param img PDFImage to set the name of * @return the name given to the image */ public String setImageName(PDFImage img) { imageid++; img.setName("/Image"+imageid); return img.getName(); } /** * <p>Set the PDFInfo object, which contains author, title, * keywords, etc</p> * @param info a PDFInof object */ public void setPDFInfo(PDFInfo info) { this.info = info; } /** * <p>Get the PDFInfo object, which contains author, title, keywords, * etc</p> * @return the PDFInfo object for this document. */ public PDFInfo getPDFInfo() { return this.info; } /** * This writes the document to an OutputStream. * * <p><b>Note:</b> You can call this as many times as you wish, as long as * the calls are not running at the same time. * * <p>Also, objects can be added or amended between these calls. * * <p>Also, the OutputStream is not closed, but will be flushed on * completion. It is up to the caller to close the stream. * * @param os OutputStream to write the document to * @exception IOException on error */ public void write(OutputStream os) throws IOException { PDFOutput pos = new PDFOutput(os); // Write each object to the OutputStream. We call via the output // as that builds the xref table for(PDFObject o : objects) { pos.write(o); } // Finally close the output, which writes the xref table. pos.close(); // and flush the output stream to ensure everything is written. os.flush(); } } // end class PDFDocument