code: /*
   * $Id: PDFJob.java,v 1.3 2007/08/26 18:56:35 gil1 Exp $
   *
   * $Date: 2007/08/26 18:56:35 $
   *
   * 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 pdf;
  
  import java.awt.Dimension;
  import java.awt.Graphics;
  import java.awt.PrintGraphics;
  import java.awt.PrintJob;
  import java.awt.Rectangle;
  import java.awt.print.PageFormat;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.io.PrintWriter;
  import java.io.Serializable;
  
  
  /**
   * <p>This class extends awt's PrintJob, to provide a simple method of writing
   * PDF documents.</p>
   *
   * <p>You can use this with any code that uses Java's printing mechanism. It
   * does include a few extra methods to provide access to some of PDF's features
   * like annotations, or outlines.</p>
   *
   *
   * @author Peter T Mount, http://www.retep.org.uk/pdf/
   * @author Eric Z. Beard, ericzbeard@hotmail.com
   * @version $Revision: 1.3 $, $Date: 2007/08/26 18:56:35 $
   */
  public class PDFJob extends PrintJob implements Serializable
  {
    /*
     * NOTE: The original class is the work of Peter T. Mount, who released it 
     * in the uk.org.retep.pdf package.  It was modified by Eric Z. Beard as 
     * follows: 
     * The package name was changed to gnu.jpdf
     * The formatting was changed a little bit.
     * This used to subclass an abstract class with the same name in 
     *   another package to support jdk1.1. Now it's one concrete class, 
     *   with no jdk1.1 support
     * Instances of PDFJob come directly from constructors, not 
     *   static methods in PDFDocument (which used to be PDF)
     * It is still licensed under the LGPL.
     */
  
  
    /**
     * This is the OutputStream the PDF file will be written to when complete
     * Note: This is transient, as it's not valid after being Serialized.
     */
    protected transient OutputStream os;
    
    /**
     * This is the PDF file being constructed
     */
    protected PDFDocument pdfDocument;
    
    /**
     * This is the current page being constructed by the last getGraphics()
     * call
     */
    protected PDFPage page;
    
    /**
     * This is the page number of the current page
     */
    protected int pagenum;
  
  
    // Constructors
  
    /**
     * <p>This constructs the job. This method must be used when creating a
     * template pdf file, ie one that is Serialised by one application, and
     * then restored by another.</p>
     *
     * <p>ezb 20011115 - Haven't done anything with templates yet, don't know 
     * how/if they are implemented</p>
     */
    public PDFJob() {
      this(null);
    }
    
    /**
     * <p>This constructs the job.  This is the primary constructor that 
     * will be used for creating pdf documents with this package.  The 
     * specified output stream is a handle to the .pdf file you wish to 
     * create.</p>
     *
     * @param os - <code>OutputStream</code> to use for the pdf output
     */
    public PDFJob(OutputStream os) {
      this(os, "PDF Doc");
    }
    
    /**
     * <p>This constructs the job.  This is the primary constructor that 
     * will be used for creating pdf documents with this package.  The 
     * specified output stream is a handle to the .pdf file you wish to 
     * create.</p>
     *
     * <p>Use this constructor if you want to give the pdf document a name 
     * other than the default of "PDF Doc"</p>
     *  
     * @param os - <code>OutputStream</code> to use for the pdf output
     * @param title a <code>String</code> value
     */
    public PDFJob(OutputStream os, String title) {
      this.os = os;
      this.pdfDocument = new PDFDocument();
      pagenum = 0;
      pdfDocument.getPDFInfo().setTitle(title);
    }
  
  
    /**
     * <p>This returns a graphics object that can be used to draw on a page.
     * In PDF, this will be a new page within the document.</p>
     *
     * @param orient - the <code>int</code> Orientation of the new page, 
     *        as defined in <code>PDFPage</code>
     * @return Graphics object to draw.
     * @see PageFormat#PORTRAIT
     * @see PageFormat#LANDSCAPE
     * @see PageFormat#REVERSE_LANDSCAPE
     */
    public Graphics getGraphics(int orient) {
      // create a new page
      page = new PDFPage(orient);
      pdfDocument.add(page);
      pagenum++;
      
      // Now create a Graphics object to draw onto the page
      return new graphic(page,this);
    }
      
  
    /**
     * <p>This returns a graphics object that can be used to draw on a page.
     * In PDF, this will be a new page within the document.</p>
     *
     * @param pageFormat PageFormat describing the page size
     * @return Graphics object to draw.
     */
    public Graphics getGraphics(PageFormat pageFormat) {
      // create a new page
      page = new PDFPage(pageFormat);
      pdfDocument.add(page);
      pagenum++;
      
      // Now create a Graphics object to draw onto the page
      return new graphic(page,this);
    }
    
    
    
    
    /**
     * <p>This writes the PDF document to the OutputStream, finishing the
     * document.</p>
     */
    public void end() {
      try {
        pdfDocument.write(os);
      } catch(IOException ioe) {
        // Ideally we should throw this. However, PrintJob doesn't throw
        // anything, so we will print the Stack Trace instead.
        ioe.printStackTrace();
      } finally {
      	try {
      		if (os != null) {
      			os.close();
      		}
      	} catch (Exception e) {
      		e.printStackTrace();
      	}
      }
      
      // This should mark us as dead
      os = null;
      pdfDocument = null;
    }
   
  
  
    /**
     * <p>This returns a graphics object that can be used to draw on a page.
     * In PDF, this will be a new page within the document.</p>
     *
     * <p>This new page will by default be oriented as a portrait</p>
     *
     * @return a <code>Graphics</code> object to draw to.
     */
    public Graphics getGraphics() {
      return getGraphics(PageFormat.PORTRAIT);
    }
    
    
    
    /**
     * <p>Returns the page dimension</p>
     *
     * @return a <code>Dimension</code> instance, the size of the page
     */
    public Dimension getPageDimension() {
  		if (page == null) {
  			System.err.println("PDFJob.getPageDimension(), page is null");
  		}
  		return page.getDimension();
  	}
    
    
    /**
     * <p>How about a setPageDimension(Rectangle media) ?? </p>
     */
    
  
    /**
     * This returns the page resolution.
     *
     * <p>This is the PDF (and Postscript) device resolution of 72 dpi
     * (equivalent to 1 point).</p>
     *
     * @return an <code>int</code>, the resolution in pixels per inch
     */
    public int getPageResolution() {
      return 72;
    }
    
  
  
  
    /**
     * <p>In AWT's PrintJob, this would return true if the user requested that the
     * file is printed in reverse order. For PDF's this is not applicable, so
     * it will always return false.</p>
     *
     * @return false
     */
    public boolean lastPageFirst() {
      return false;
    }
    
    //======== END OF PrintJob extension ==========
   
  
  
    /**
     * Returns the PDFDocument object for this document. 
     * Useful for gaining access to
     * the internals of PDFDocument.
     * @return the PDF object
     */
    public PDFDocument getPDFDocument() {
      return pdfDocument;
    }
    
    /**
     * <p>Returns the current PDFPage being worked on. Useful for working on
     * Annotations (like links), etc.</p>
     *
     * @return the <code>PDFPage</code> currently being constructed
     */
    public PDFPage getCurrentPage() {
      return page;
    }
    
    /**
     * <p>Returns the current page number.
     * Useful if you need to include one in the document</p>
     *
     * @return the <code>int</code> current page number
     */
    public int getCurrentPageNumber() {
      return pagenum;
    }
   
  
    
    /**
     * <p>This method attaches an outline to the current page being generated.
     * When selected, the outline displays the top of the page.</p>
     *
     * @param title a <code>String</code>, the title of the Outline
     * @return a <code>PDFOutline</code> object that was created, 
     *         for adding sub-outline's if required.
     */
    public PDFOutline addOutline(String title) {
      return page.addOutline(title);
    }
    
    /**
     * <p>This method attaches an outline to the current page being generated.
     * When selected, the outline displays the specified region.</p>
     *
     * @param title Outline title to attach
     * @param x Left coordinate of region
     * @param y Top coordinate of region
     * @param w width of region
     * @param h height of region
     * @return the <code>PDFOutline</code> object created, 
     *         for adding sub-outline's if required.
     */
    public PDFOutline addOutline(String title,int x,int y,int w,int h) {
      return page.addOutline(title,x,y,w,h);
    }
    
    /**
     * Convenience method: Adds a text note to the document.
     * @param note Text of the note
     * @param x Coordinate of note
     * @param y Coordinate of note
     * @param w Width of the note
     * @param h Height of the note
     * @return Returns the annotation, so other settings can be changed.
     */
    public PDFAnnot addNote(String note,int x,int y,int w,int h) {
      return page.addNote(note,x,y,w,h);
    }
    
    
    /**
     * <p>This inner class extends PDFGraphics for the PrintJob.</p>
     *
     * <p>Like with java.awt, Graphics instances created with PrintJob implement
     * the PrintGraphics interface. Here we implement that method, and overide
     * PDFGraphics.create() method, so all instances have this interface.</p>
     */
    class graphic extends PDFGraphics implements PrintGraphics {
      /**
       * The PDFJob we are linked with
       */
      private PDFJob job;
      
      /**
       * @param page to attach to
       * @param job PDFJob containing this graphic
       */
      graphic(PDFPage page,PDFJob job) {
        super();
        this.init(page);
        this.job = job;
      }
      
      /**
       * This is used by our version of create()
       */
      graphic(PDFPage page,PDFJob job,PrintWriter pw) {
        super();
        this.init(page,pw);
        this.job = job;
      }
      
      /**
       * This returns a child instance of this Graphics object. As with AWT,
       * the affects of using the parent instance while the child exists,
       * is not determined.
       *
       * <p>This method is used to make a new Graphics object without 
       * going to a new page</p>
       *
       * <p>Once complete, the child should be released with it's dispose()
       * method which will restore the graphics state to it's parent.
       *
       * @return Graphics object
       */
      public Graphics create() {
        closeBlock();
        graphic g = new graphic(getPage(),job,getWriter());
        
        // The new instance inherits a few items
        g.clipRectangle = new Rectangle(clipRectangle);
        
        return (Graphics) g;
      }
      
      /**
       * This is the PrintGraphics interface
       * @return PrintJob for this object
       */
      public PrintJob getPrintJob() {
        return (PrintJob)job;
      }
      
    } // end inner class graphic
    
  } // end class PDFJob
  
  