Chapter 6: Working with existing PDFs

These examples were written in the context of Chapter 6 of the book "iText in Action - Second Edition".

Files: 
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
 
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
 
import part1.chapter01.HelloWorldLandscape1;
import part1.chapter01.HelloWorldLandscape2;
import part1.chapter03.MovieTemplates;
import part1.chapter05.Hero1;
 
public class PageInformation {
 
	/** The resulting text file with info about a PDF. */
    public static final String RESULT
        = "results/part2/chapter06/page_info.txt";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws DocumentException, IOException {
    	// Use old examples to create PDFs
        HelloWorldLandscape1.main(args);
        HelloWorldLandscape2.main(args);
        MovieTemplates.main(args);
        Hero1.main(args);
        // Inspecting PDFs
        PrintWriter writer = new PrintWriter(new FileOutputStream(RESULT));
        inspect(writer, HelloWorldLandscape1.RESULT);
        inspect(writer, HelloWorldLandscape2.RESULT);
        inspect(writer, MovieTemplates.RESULT);
        inspect(writer, Hero1.RESULT);
        writer.close();
    }
 
    /**
     * Inspect a PDF file and write the info to a txt file
     * @param writer Writer to a text file
     * @param filename Path to the PDF file
     * @throws IOException
     */
    public static void inspect(PrintWriter writer, String filename)
        throws IOException {
        PdfReader reader = new PdfReader(filename);
        writer.println(filename);
        writer.print("Number of pages: ");
        writer.println(reader.getNumberOfPages());
        Rectangle mediabox = reader.getPageSize(1);
        writer.print("Size of page 1: [");
        writer.print(mediabox.getLeft());
        writer.print(',');
        writer.print(mediabox.getBottom());
        writer.print(',');
        writer.print(mediabox.getRight());
        writer.print(',');
        writer.print(mediabox.getTop());
        writer.println("]");
        writer.print("Rotation of page 1: ");
        writer.println(reader.getPageRotation(1));
        writer.print("Page size with rotation of page 1: ");
        writer.println(reader.getPageSizeWithRotation(1));
        writer.print("Is rebuilt? ");
        writer.println(reader.isRebuilt());
        writer.print("Is encrypted? ");
        writer.println(reader.isEncrypted());
        writer.println();
        writer.flush();
        reader.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
import part1.chapter03.MovieTemplates;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
 
public class MemoryInfo {
 
	/** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/memory_info.txt";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// Use a previous example to create a PDF
        MovieTemplates.main(args);
        // Create a writer for a report file
        PrintWriter writer
            = new PrintWriter(new FileOutputStream(RESULT));
        garbageCollect();
        // Do a full read
        fullRead(writer, MovieTemplates.RESULT);
        // Do a partial read
        partialRead(writer, MovieTemplates.RESULT);
        // Close the text file writer
        writer.close();
    }
 
    /**
     * Do a full read of a PDF file
     * @param writer a writer to a report file
     * @param filename the file to read
     * @throws IOException
     */
    public static void fullRead(PrintWriter writer, String filename)
        throws IOException {
        long before = getMemoryUse();
        PdfReader reader = new PdfReader(filename);
        reader.getNumberOfPages();
        writer.println(String.format("Memory used by full read: %d",
                    getMemoryUse() - before));
        writer.flush();
        reader.close();
    }
 
    /**
     * Do a partial read of a PDF file
     * @param writer a writer to a report file
     * @param filename the file to read
     * @throws IOException
     */
    public static void partialRead(PrintWriter writer, String filename)
        throws IOException {
        long before = getMemoryUse();
        PdfReader reader = new PdfReader(
                new RandomAccessFileOrArray(filename), null);
        reader.getNumberOfPages();
        writer.println(String.format("Memory used by partial read: %d",
                    getMemoryUse() - before));
        writer.flush();
        reader.close();
    }
 
    /**
     * Returns the current memory use.
     * 
     * @return the current memory use
     */
    public static long getMemoryUse() {
        garbageCollect();
        garbageCollect();
        garbageCollect();
        garbageCollect();
        long totalMemory = Runtime.getRuntime().totalMemory();
        garbageCollect();
        garbageCollect();
        long freeMemory = Runtime.getRuntime().freeMemory();
        return (totalMemory - freeMemory);
    }
 
    /**
     * Makes sure all garbage is cleared from the memory.
     */
    public static void garbageCollect() {
        try {
            System.gc();
            Thread.sleep(200);
            System.runFinalization();
            Thread.sleep(200);
            System.gc();
            Thread.sleep(200);
            System.runFinalization();
            Thread.sleep(200);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
 
import part1.chapter03.MovieTemplates;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
 
public class SelectPages {
 
	/** A resulting PDF file. */
    public static final String RESULT1 = "results/part2/chapter06/timetable_stamper.pdf";
	/** A resulting PDF file. */
    public static final String RESULT2 = "results/part2/chapter06/timetable_copy.pdf"; 
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args) throws IOException, DocumentException {
        new MovieTemplates().createPdf(MovieTemplates.RESULT);
        PdfReader reader = new PdfReader(MovieTemplates.RESULT);
        reader.selectPages("4-8");
        manipulateWithStamper(reader);
        manipulateWithCopy(reader);
        reader.close();
    }
 
    /**
     * Creates a new PDF based on the one in the reader
     * @param reader a reader with a PDF file
     * @throws IOException
     * @throws DocumentException
     */
    private static void manipulateWithStamper(PdfReader reader)
        throws IOException, DocumentException {
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(RESULT1));
        stamper.close();
    }
 
    /**
     * Creates a new PDF based on the one in the reader
     * @param reader a reader with a PDF file
     * @throws IOException
     * @throws DocumentException
     */
    private static void manipulateWithCopy(PdfReader reader)
        throws IOException, DocumentException {
        int n = reader.getNumberOfPages();
        Document document = new Document();
        PdfCopy copy = new PdfCopy(document, new FileOutputStream(RESULT2));
        document.open();
        for (int i = 0; i < n;) {
            copy.addPage(copy.getImportedPage(reader, ++i));
        }
        document.close();
    }
 
 
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
 
import part1.chapter03.MovieTemplates;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
 
public class ImportingPages1 {
 
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/time_table_imported1.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// Use old example to create PDF
        new MovieTemplates().createPdf(MovieTemplates.RESULT);
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        PdfPTable table = new PdfPTable(2);
        PdfReader reader = new PdfReader(MovieTemplates.RESULT);
        int n = reader.getNumberOfPages();
        PdfImportedPage page;
        for (int i = 1; i <= n; i++) {
            page = writer.getImportedPage(reader, i);
            table.addCell(Image.getInstance(page));
        }
        document.add(table);
        // step 5
        document.close();
        reader.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
 
import part1.chapter03.MovieTemplates;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
 
public class ImportingPages2 {
 
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/time_table_imported2.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
        // use old example to create PDF
    	new MovieTemplates().createPdf(MovieTemplates.RESULT);
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        PdfReader reader = new PdfReader(MovieTemplates.RESULT);
        int n = reader.getNumberOfPages();
        PdfImportedPage page;
        PdfPTable table = new PdfPTable(2);
        for (int i = 1; i <= n; i++) {
            page = writer.getImportedPage(reader, i);
            table.getDefaultCell().setRotation(-page.getRotation());
            table.addCell(Image.getInstance(page));
        }
        document.add(table);
        // step 5
        document.close();
        reader.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
 
public class Layers {
 
    /** The resulting PDF. */
    public static final String SOURCE
        = "results/part2/chapter06/layers_orig.pdf";
    /** The resulting PDF. */
    public static final String RESULT
        = "results/part2/chapter06/layers.pdf";
    /** The movie poster. */
    public static final String RESOURCE
        = "resources/img/loa.jpg";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
        new Layers().createPdf(SOURCE);
        // Create a reader
        PdfReader reader = new PdfReader(SOURCE);
        // step 1
        Document document = new Document(PageSize.A5.rotate());
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        PdfContentByte canvas = writer.getDirectContent();
        PdfImportedPage page;
        BaseFont bf
            = BaseFont.createFont(BaseFont.ZAPFDINGBATS, "", BaseFont.EMBEDDED);
        for (int i = 0; i < reader.getNumberOfPages(); ) {
            page = writer.getImportedPage(reader, ++i);
            canvas.addTemplate(page, 1f, 0, 0.4f, 0.4f, 72, 50 * i);
            canvas.beginText();
            canvas.setFontAndSize(bf, 20);
            canvas.showTextAligned(Element.ALIGN_CENTER,
                String.valueOf((char)(181 + i)), 496, 150 + 50 * i, 0);
            canvas.endText();
        }
        // step 5
        document.close();
        reader.close();
    }
 
    /**
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws    DocumentException 
     * @throws    IOException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException {
        // step 1
        Document document = new Document(PageSize.POSTCARD, 30, 30, 30, 30);
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document,
                new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        PdfContentByte under = writer.getDirectContentUnder();
        // Page 1: a rectangle
        drawRectangle(under, PageSize.POSTCARD.getWidth(), PageSize.POSTCARD.getHeight());
        under.setRGBColorFill(0xFF, 0xD7, 0x00);
        under.rectangle(5, 5, PageSize.POSTCARD.getWidth() - 10, PageSize.POSTCARD.getHeight() - 10);
        under.fill();
        document.newPage();
        // Page 2: an image
        drawRectangle(under, PageSize.POSTCARD.getWidth(), PageSize.POSTCARD.getHeight());
        Image img = Image.getInstance(RESOURCE);
        img.setAbsolutePosition((PageSize.POSTCARD.getWidth() - img.getScaledWidth()) / 2,
                (PageSize.POSTCARD.getHeight() - img.getScaledHeight()) / 2);
        document.add(img);
        document.newPage();
        // Page 3: the words "Foobar Film Festival"
        drawRectangle(under, PageSize.POSTCARD.getWidth(), PageSize.POSTCARD.getHeight());;
        Paragraph p = new Paragraph("Foobar Film Festival", new Font(FontFamily.HELVETICA, 22));
        p.setAlignment(Element.ALIGN_CENTER);
        document.add(p);
        document.newPage();
        // Page 4: the words "SOLD OUT"
        drawRectangle(under, PageSize.POSTCARD.getWidth(), PageSize.POSTCARD.getHeight());
        PdfContentByte over = writer.getDirectContent();
        over.saveState();
        float sinus = (float)Math.sin(Math.PI / 60);
        float cosinus = (float)Math.cos(Math.PI / 60);
        BaseFont bf = BaseFont.createFont();
        over.beginText();
        over.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
        over.setLineWidth(1.5f);
        over.setRGBColorStroke(0xFF, 0x00, 0x00);
        over.setRGBColorFill(0xFF, 0xFF, 0xFF);
        over.setFontAndSize(bf, 36);
        over.setTextMatrix(cosinus, sinus, -sinus, cosinus, 50, 324);
        over.showText("SOLD OUT");
        over.setTextMatrix(0, 0);
        over.endText();
        over.restoreState();
        // step 5
        document.close();
    }
 
    /**
     * Draws a rectangle
     * @param content the direct content layer
     * @param width the width of the rectangle
     * @param height the height of the rectangle
     */
    public static void drawRectangle(PdfContentByte content, float width, float height) {
        content.saveState();
        PdfGState state = new PdfGState();
        state.setFillOpacity(0.6f);
        content.setGState(state);
        content.setRGBColorFill(0xFF, 0xFF, 0xFF);
        content.setLineWidth(3);
        content.rectangle(0, 0, width, height);
        content.fillStroke();
        content.restoreState();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
 
public class Superimposing {
 
    /** The resulting PDF. */
    public static final String SOURCE
        = "results/part2/chapter06/opening.pdf";
    /** The resulting PDF. */
    public static final String RESULT
        = "results/part2/chapter06/festival_opening.pdf";
    /** The movie poster. */
    public static final String RESOURCE
        = "resources/img/loa.jpg";
 
    /**
     * Main method.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
        new Superimposing().createPdf(SOURCE);
        // Create a reader object
        PdfReader reader = new PdfReader(SOURCE);
        // step 1
        Document document = new Document(PageSize.POSTCARD);
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        PdfContentByte canvas = writer.getDirectContent();
        PdfImportedPage page;
        for (int i = 1; i <= reader.getNumberOfPages(); i++) {
            page = writer.getImportedPage(reader, i);
            canvas.addTemplate(page, 1f, 0, 0, 1, 0, 0);
        }
        // step 5
        document.close();
        reader.close();
    }
 
    /**
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws    DocumentException 
     * @throws    IOException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException {
        // step 1
        Document document = new Document(PageSize.POSTCARD, 30, 30, 30, 30);
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        PdfContentByte under = writer.getDirectContentUnder();
        // page 1: rectangle
        under.setRGBColorFill(0xFF, 0xD7, 0x00);
        under.rectangle(5, 5,
            PageSize.POSTCARD.getWidth() - 10, PageSize.POSTCARD.getHeight() - 10);
        under.fill();
        document.newPage();
        // page 2: image
        Image img = Image.getInstance(RESOURCE);
        img.setAbsolutePosition(
            (PageSize.POSTCARD.getWidth() - img.getScaledWidth()) / 2,
            (PageSize.POSTCARD.getHeight() - img.getScaledHeight()) / 2);
        document.add(img);
        document.newPage();
        // page 3: the words "Foobar Film Festival"
        Paragraph p = new Paragraph("Foobar Film Festival", new Font(FontFamily.HELVETICA, 22));
        p.setAlignment(Element.ALIGN_CENTER);
        document.add(p);
        document.newPage();
        // page 4: the words "SOLD OUT"
        PdfContentByte over = writer.getDirectContent();
        over.saveState();
        float sinus = (float)Math.sin(Math.PI / 60);
        float cosinus = (float)Math.cos(Math.PI / 60);
        BaseFont bf = BaseFont.createFont();
        over.beginText();
        over.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
        over.setLineWidth(1.5f);
        over.setRGBColorStroke(0xFF, 0x00, 0x00);
        over.setRGBColorFill(0xFF, 0xFF, 0xFF);
        over.setFontAndSize(bf, 36);
        over.setTextMatrix(cosinus, sinus, -sinus, cosinus, 50, 324);
        over.showText("SOLD OUT");
        over.setTextMatrix(0, 0);
        over.endText();
        over.restoreState();
        // step 5
        document.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Set;
import java.util.TreeSet;
 
import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.FilmFonts;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.MovieComparator;
import com.lowagie.filmfestival.PojoFactory;
import com.lowagie.filmfestival.PojoToElementFactory;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.GrayColor;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
 
public class Stationery extends PdfPageEventHelper {
 
    /** The original PDF. */
    public static final String STATIONERY
        = "results/part2/chapter06/stationery.pdf";
    /** The resulting PDF. */
    public static final String RESULT
        = "results/part2/chapter06/text_on_stationery.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        Stationery stationary = new Stationery();
        createStationary(STATIONERY);
        stationary.createPdf(RESULT);
    }
 
    /**
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws    DocumentException 
     * @throws    IOException
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws SQLException, IOException, DocumentException {
    	// Create the database connection
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        // step 1
        Document document = new Document(PageSize.A4, 36, 36, 72, 36);
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
        useStationary(writer);
        // step 3
        document.open();
        // step 4
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT country, id FROM film_country ORDER BY country");
        while (rs.next()) {
            document.add(new Paragraph(rs.getString("country"), FilmFonts.BOLD));
            document.add(Chunk.NEWLINE);
            Set<Movie> movies = 
                new TreeSet<Movie>(new MovieComparator(MovieComparator.BY_YEAR));
            movies.addAll(PojoFactory.getMovies(connection, rs.getString("id")));
            for(Movie movie : movies) {
                document.add(new Paragraph(movie.getMovieTitle(), FilmFonts.BOLD));
                if (movie.getOriginalTitle() != null)
                    document.add(new Paragraph(movie.getOriginalTitle(), FilmFonts.ITALIC));
                document.add(new Paragraph(
                    String.format("Year: %d; run length: %d minutes",
                    movie.getYear(), movie.getDuration()), FilmFonts.NORMAL));
                document.add(PojoToElementFactory.getDirectorList(movie));
            }
            document.newPage();
        }
        // step 5
        document.close();
        // Close the database connection
        connection.close();
    }
 
    /** Imported page with the stationery. */
    protected PdfImportedPage page;
 
    /**
     * Initialize the imported page.
     * @param writer The PdfWriter
     * @throws IOException
     */
    public void useStationary(PdfWriter writer) throws IOException {
        writer.setPageEvent(this);
        PdfReader reader = new PdfReader(STATIONERY);
        page = writer.getImportedPage(reader, 1);
    }
 
    /**
     * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(
     *      com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
     */
    public void onEndPage(PdfWriter writer, Document document) {
        writer.getDirectContentUnder().addTemplate(page, 0, 0);
    }
 
    /**
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws    DocumentException 
     * @throws    IOException
     * @throws    SQLException
     */
    public static void createStationary(String filename)
        throws IOException, DocumentException {
        // step 1
    	Document document = new Document();
    	// step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        PdfPTable table = new PdfPTable(1);
        table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(new Phrase("FOOBAR FILM FESTIVAL", FilmFonts.BOLD));
        document.add(table);
        Font font = new Font(FontFamily.HELVETICA, 52, Font.BOLD, new GrayColor(0.75f));
        ColumnText.showTextAligned(writer.getDirectContentUnder(),
                Element.ALIGN_CENTER, new Phrase("FOOBAR FILM FESTIVAL", font),
                297.5f, 421, 45);
        // step 5
        document.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
 
public class NUpTool {
 
    /** Format of the resulting PDF files. */
    public static final String RESULT
        = "results/part2/chapter06/result%dup.pdf";
 
    /**
     * Manipulates a PDF file src with the file dest as result
     * @param src the original PDF
     * @param dest the resulting PDF
     * @param pow the PDF will be N-upped with N = Math.pow(2, pow);
     * @throws IOException
     * @throws DocumentException
     * @throws SQLException
     */
    public void manipulatePdf(String src, String dest, int pow)
        throws IOException, DocumentException {
    	// reader for the src file
        PdfReader reader = new PdfReader(src);
        // initializations
        Rectangle pageSize = reader.getPageSize(1);
        Rectangle newSize = (pow % 2) == 0 ?
            new Rectangle(pageSize.getWidth(), pageSize.getHeight()) :
            new Rectangle(pageSize.getHeight(), pageSize.getWidth());
        Rectangle unitSize = new Rectangle(pageSize.getWidth(), pageSize.getHeight());
        for (int i = 0; i < pow; i++) {
            unitSize = new Rectangle(unitSize.getHeight() / 2, unitSize.getWidth());
        }
        int n = (int)Math.pow(2, pow);
        int r = (int)Math.pow(2, pow / 2);
        int c = n / r;
        // step 1
        Document document = new Document(newSize, 0, 0, 0, 0);
        // step 2
        PdfWriter writer
           = PdfWriter.getInstance(document, new FileOutputStream(String.format(dest, n)));
        // step 3
        document.open();
        // step 4
        PdfContentByte cb = writer.getDirectContent();
        PdfImportedPage page;
        Rectangle currentSize;
        float offsetX, offsetY, factor;
        int total = reader.getNumberOfPages();
        for (int i = 0; i < total; ) {
            if (i % n == 0) {
                document.newPage();
            }
            currentSize = reader.getPageSize(++i);
            factor = Math.min(
                unitSize.getWidth() / currentSize.getWidth(),
                unitSize.getHeight() / currentSize.getHeight());
            offsetX = unitSize.getWidth() * ((i % n) % c)
              + (unitSize.getWidth() - (currentSize.getWidth() * factor)) / 2f;
            offsetY = newSize.getHeight() - (unitSize.getHeight() * (((i % n) / c) + 1))
              + (unitSize.getHeight() - (currentSize.getHeight() * factor)) / 2f;
            page = writer.getImportedPage(reader, i);
            cb.addTemplate(page, factor, 0, 0, factor, offsetX, offsetY);
        }
        // step 5
        document.close();
        reader.close();
    }
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        Stationery.main(args);
        new NUpTool().manipulatePdf(Stationery.RESULT, RESULT, 1);
        new NUpTool().manipulatePdf(Stationery.RESULT, RESULT, 2);
        new NUpTool().manipulatePdf(Stationery.RESULT, RESULT, 3);
        new NUpTool().manipulatePdf(Stationery.RESULT, RESULT, 4);
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
 
public class TilingHero {
 
    /** The original PDF file. */
    public static final String RESOURCE
        = "resources/pdfs/hero.pdf";
 
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/superman.pdf";
 
    /**
     * Manipulates a PDF file src with the file dest as result
     * @param src the original PDF
     * @param dest the resulting PDF
     * @throws IOException
     * @throws DocumentException
     */
    public void manipulatePdf(String src, String dest)
        throws IOException, DocumentException {
    	// Creating a reader
        PdfReader reader = new PdfReader(src);
        Rectangle pagesize = reader.getPageSizeWithRotation(1);
        // step 1
        Document document = new Document(pagesize);
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(dest));
        // step 3
        document.open();
        // step 4
        PdfContentByte content = writer.getDirectContent();
        PdfImportedPage page = writer.getImportedPage(reader, 1);
        // adding the same page 16 times with a different offset
        float x, y;
        for (int i = 0; i < 16; i++) {
            x = -pagesize.getWidth() * (i % 4);
            y = pagesize.getHeight() * (i / 4 - 3);
            content.addTemplate(page, 4, 0, 0, 4, x, y);
            document.newPage();
        }
        // step 4
        document.close();
        reader.close();
    }
 
    /**
     * Main method.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
        new TilingHero().manipulatePdf(RESOURCE, RESULT);
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
 
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
 
import part1.chapter01.HelloWorldLandscape1;
import part1.chapter01.HelloWorldLandscape2;
 
public class StampText {
    /** A resulting PDF file. */
    public static final String RESULT1
        = "results/part2/chapter06/hello1.pdf";
    /** A resulting PDF file. */
    public static final String RESULT2
        = "results/part2/chapter06/hello2.pdf";
    /** A resulting PDF file. */
    public static final String RESULT3
        = "results/part2/chapter06/hello3.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws DocumentException, IOException {
        HelloWorldLandscape1.main(args);
        HelloWorldLandscape2.main(args);
        stamp(HelloWorldLandscape1.RESULT, RESULT1);
        stampIgnoreRotation(HelloWorldLandscape1.RESULT, RESULT2);
        stamp(HelloWorldLandscape2.RESULT, RESULT3);
 
    }
 
    /**
     * Manipulates a PDF file src with the file dest as result
     * @param src the original PDF
     * @param dest the resulting PDF
     * @throws IOException
     * @throws DocumentException
     */
    public static void stamp(String src, String dest)
        throws IOException, DocumentException {
        PdfReader reader = new PdfReader(src);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        PdfContentByte canvas = stamper.getOverContent(1);
        ColumnText.showTextAligned(canvas,
                Element.ALIGN_LEFT, new Phrase("Hello people!"), 36, 540, 0);
        stamper.close();
        reader.close();
    }
 
    /**
     * Manipulates a PDF file src with the file dest as result
     * @param src the original PDF
     * @param dest the resulting PDF
     * @throws IOException
     * @throws DocumentException
     */
    public static void stampIgnoreRotation(String src, String dest)
        throws IOException, DocumentException {
        PdfReader reader = new PdfReader(src);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        stamper.setRotateContents(false);
        PdfContentByte canvas = stamper.getOverContent(1);
        ColumnText.showTextAligned(canvas,
                Element.ALIGN_LEFT, new Phrase("Hello people!"), 36, 540, 0);
        stamper.close();
        reader.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Set;
import java.util.TreeSet;
 
import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.FilmFonts;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.MovieComparator;
import com.lowagie.filmfestival.PojoFactory;
import com.lowagie.filmfestival.PojoToElementFactory;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
 
public class TwoPasses {
 
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/page_x_of_y.pdf";
 
    /**
     * Main method.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws SQLException, DocumentException, IOException {
 
    	// FIRST PASS, CREATE THE PDF WITHOUT HEADER
 
    	// Create a database connection
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        // step 1
        Document document = new Document(PageSize.A4, 36, 36, 54, 36);
        // step 2
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PdfWriter.getInstance(document, baos);
        // step 3
        document.open();
        // step 4
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT country, id FROM film_country ORDER BY country");
        while (rs.next()) {
            document.add(new Paragraph(rs.getString("country"), FilmFonts.BOLD));
            document.add(Chunk.NEWLINE);
            Set<Movie> movies = 
                new TreeSet<Movie>(new MovieComparator(MovieComparator.BY_YEAR));
            movies.addAll(PojoFactory.getMovies(connection, rs.getString("id")));
            for(Movie movie : movies) {
                document.add(new Paragraph(movie.getMovieTitle(), FilmFonts.BOLD));
                if (movie.getOriginalTitle() != null)
                    document.add(
                        new Paragraph(movie.getOriginalTitle(), FilmFonts.ITALIC));
                document.add(new Paragraph(
                    String.format("Year: %d; run length: %d minutes",
                    movie.getYear(), movie.getDuration()), FilmFonts.NORMAL));
                document.add(PojoToElementFactory.getDirectorList(movie));
            }
            document.newPage();
        }
        // step 5
        document.close();
        // Close the database connection
        connection.close();
 
        // SECOND PASS, ADD THE HEADER
 
        // Create a reader
        PdfReader reader = new PdfReader(baos.toByteArray());
        // Create a stamper
        PdfStamper stamper
            = new PdfStamper(reader, new FileOutputStream(RESULT));
        // Loop over the pages and add a header to each page
        int n = reader.getNumberOfPages();
        for (int i = 1; i <= n; i++) {
            getHeaderTable(i, n).writeSelectedRows(
                    0, -1, 34, 803, stamper.getOverContent(i));
        }
        // Close the stamper
        stamper.close();
        reader.close();
    }
 
    /**
     * Create a header table with page X of Y
     * @param x the page number
     * @param y the total number of pages
     * @return a table that can be used as header
     */
    public static PdfPTable getHeaderTable(int x, int y) {
        PdfPTable table = new PdfPTable(2);
        table.setTotalWidth(527);
        table.setLockedWidth(true);
        table.getDefaultCell().setFixedHeight(20);
        table.getDefaultCell().setBorder(Rectangle.BOTTOM);
        table.addCell("FOOBAR FILMFESTIVAL");
        table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(String.format("Page %d of %d", x, y));
        return table;
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Set;
import java.util.TreeSet;
 
import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.FilmFonts;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.MovieComparator;
import com.lowagie.filmfestival.PojoFactory;
import com.lowagie.filmfestival.PojoToElementFactory;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
 
public class StampStationery {
    /** The original PDF file. */
    public static final String ORIGINAL
        = "results/part2/chapter06/original.pdf";
    /** The resulting PDF. */
    public static final String RESULT
        = "results/part2/chapter06/stamped_stationary.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        Stationery.createStationary(Stationery.STATIONERY);
        StampStationery stationary = new StampStationery();
        stationary.createPdf(ORIGINAL);
        stationary.manipulatePdf(ORIGINAL, Stationery.STATIONERY, RESULT);
    }
 
    /**
     * Manipulates a PDF file src with the file dest as result
     * @param src the original PDF
     * @param stationery a PDF that will be added as background
     * @param dest the resulting PDF
     * @throws IOException
     * @throws DocumentException
     */
    public void manipulatePdf(String src, String stationery, String dest)
        throws IOException, DocumentException {
    	// Create readers
        PdfReader reader = new PdfReader(src);
        PdfReader s_reader = new PdfReader(stationery);
        // Create the stamper
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        // Add the stationery to each page
        PdfImportedPage page = stamper.getImportedPage(s_reader, 1);
        int n = reader.getNumberOfPages();
        PdfContentByte background;
        for (int i = 1; i <= n; i++) {
            background = stamper.getUnderContent(i);
            background.addTemplate(page, 0, 0);
        }
        // CLose the stamper
        stamper.close();
        reader.close();
        s_reader.close();
    }
 
    /**
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws    DocumentException 
     * @throws    IOException
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws SQLException, IOException, DocumentException {
    	// Create a database connection
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        // step 1
        Document document = new Document(PageSize.A4, 36, 36, 72, 36);
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT country, id FROM film_country ORDER BY country");
        while (rs.next()) {
            document.add(new Paragraph(rs.getString("country"), FilmFonts.BOLD));
            document.add(Chunk.NEWLINE);
            Set<Movie> movies = 
                new TreeSet<Movie>(new MovieComparator(MovieComparator.BY_YEAR));
            movies.addAll(PojoFactory.getMovies(connection, rs.getString("id")));
            for(Movie movie : movies) {
                document.add(new Paragraph(movie.getMovieTitle(), FilmFonts.BOLD));
                if (movie.getOriginalTitle() != null)
                    document.add(new Paragraph(movie.getOriginalTitle(), FilmFonts.ITALIC));
                document.add(new Paragraph(
                    String.format("Year: %d; run length: %d minutes",
                    movie.getYear(), movie.getDuration()), FilmFonts.NORMAL));
                document.add(PojoToElementFactory.getDirectorList(movie));
            }
            document.newPage();
        }
        // step 5
        document.close();
        // Close the database connection
        connection.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
 
public class InsertPages {
    /** A resulting PDF. */
    public static final String RESULT1
        = "results/part2/chapter06/inserted_pages.pdf";
    /** A resulting PDF. */
    public static final String RESULT2
        = "results/part2/chapter06/reordered.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
    	// use a previous example to create a PDF
        StampStationery.main(args);
        // manipulate the PDF
        new InsertPages().manipulatePdf(StampStationery.RESULT, RESULT1);
        // reorder the pages in the PDF
        PdfReader reader = new PdfReader(RESULT1);
        reader.selectPages("3-41,1-2");
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(RESULT2));
        stamper.close();
        reader.close();
    }
 
    /**
     * Manipulates a PDF file src with the file dest as result
     * @param src the original PDF
     * @param dest the resulting PDF
     * @throws IOException
     * @throws DocumentException
     * @throws SQLException
     */
    public void manipulatePdf(String src, String dest)
        throws IOException, DocumentException, SQLException {
    	// Create a database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        // Fill a ColumnText object with data
        ResultSet rs = stm.executeQuery(
            "SELECT country, id FROM film_country ORDER BY country");
        ColumnText ct = new ColumnText(null);
        while (rs.next()) {
            ct.addElement(new Paragraph(24, new Chunk(rs.getString("country"))));
        }
        // Close the statement and database connection
        stm.close();
        connection.close();
 
        // Create a reader for the original document and for the stationery
        PdfReader reader = new PdfReader(src);
        PdfReader stationery = new PdfReader(Stationery.STATIONERY);
        // Create a stamper
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        // Create an imported page for the stationery
        PdfImportedPage page = stamper.getImportedPage(stationery, 1);
        int i = 0;
        // Add the content of the ColumnText object 
        while(true) {
            // Add a new page
            stamper.insertPage(++i, reader.getPageSize(1));
            // Add the stationary to the new page
            stamper.getUnderContent(i).addTemplate(page, 0, 0);
            // Add as much content of the column as possible
            ct.setCanvas(stamper.getOverContent(i));
            ct.setSimpleColumn(36, 36, 559, 770);
            if (!ColumnText.hasMoreText(ct.go()))
                break;
        }
        // Close the stamper
        stamper.close();
        reader.close();
        stationery.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;
 
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfReader;
 
public class FormInformation {
 
    /** The original PDF file. */
    public static final String DATASHEET
        = "resources/pdfs/datasheet.pdf";
    /** The resulting text file with the field info. */
    public static final String RESULT
        = "results/part2/chapter06/form_info.txt";    
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws DocumentException, IOException {
        // Create a writer for the report file
        PrintWriter writer
            = new PrintWriter(new FileOutputStream(RESULT));
        // Create a reader to extract info
        PdfReader reader = new PdfReader(DATASHEET);
        // Get the fields from the reader (read-only!!!)
        AcroFields form = reader.getAcroFields();
        // Loop over the fields and get info about them
        Set<String> fields = form.getFields().keySet();
        for (String key : fields) {
            writer.print(key + ": ");
            switch (form.getFieldType(key)) {
            case AcroFields.FIELD_TYPE_CHECKBOX:
                writer.println("Checkbox");
                break;
            case AcroFields.FIELD_TYPE_COMBO:
                writer.println("Combobox");
                break;
            case AcroFields.FIELD_TYPE_LIST:
                writer.println("List");
                break;
            case AcroFields.FIELD_TYPE_NONE:
                writer.println("None");
                break;
            case AcroFields.FIELD_TYPE_PUSHBUTTON:
                writer.println("Pushbutton");
                break;
            case AcroFields.FIELD_TYPE_RADIOBUTTON:
                writer.println("Radiobutton");
                break;
            case AcroFields.FIELD_TYPE_SIGNATURE:
                writer.println("Signature");
                break;
            case AcroFields.FIELD_TYPE_TEXT:
                writer.println("Text");
                break;
            default:
                writer.println("?");
            }
        }
        // Get possible values for field "CP_1"
        writer.println("Possible values for CP_1:");
        String[] states = form.getAppearanceStates("CP_1");
        for (int i = 0; i < states.length; i++) {
            writer.print(" - ");
            writer.println(states[i]);
        }
        // Get possible values for field "category"
        writer.println("Possible values for category:");
        states = form.getAppearanceStates("category");
        for (int i = 0; i < states.length - 1; i++) {
            writer.print(states[i]);
            writer.print(", ");
        }
        writer.println(states[states.length - 1]);
        // flush and close the report file
        writer.flush();
        writer.close();
        reader.close();
    }
 
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
 
import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.Director;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.PojoFactory;
import com.lowagie.filmfestival.Screening;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
 
public class FillDataSheet {
 
    /** The original PDF file. */
    public static final String DATASHEET
        = "resources/pdfs/datasheet.pdf";
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/imdb%s.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws SQLException, IOException, DocumentException {
    	// Create a database connection
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        // Get the movies
        List<Movie> movies = PojoFactory.getMovies(connection);
        PdfReader reader;
        PdfStamper stamper;
        // Fill out the data sheet form with data
        for (Movie movie : movies) {
            if (movie.getYear() < 2007)
                continue;
            reader = new PdfReader(DATASHEET);
            stamper = new PdfStamper(reader,
                    new FileOutputStream(String.format(RESULT, movie.getImdb())));
            AcroFields fields = stamper.getAcroFields();
            fields.setGenerateAppearances(true);
            fill(fields, movie);
            if (movie.getYear() == 2007)
                stamper.setFormFlattening(true);
            stamper.close();
            reader.close();
        }
        // Close the database connection
        connection.close();
    }
 
    /**
     * Fill out the fields using info from a Movie object.
     * @param form The form object
     * @param movie A movie POJO
     * @throws IOException
     * @throws DocumentException
     */
    public static void fill(AcroFields form, Movie movie)
        throws IOException, DocumentException {
    	form.setField("title", movie.getMovieTitle());
        form.setField("director", getDirectors(movie));
        form.setField("year", String.valueOf(movie.getYear()));
        form.setField("duration", String.valueOf(movie.getDuration()));
        form.setField("category", movie.getEntry().getCategory().getKeyword());
        for (Screening screening : movie.getEntry().getScreenings()) {
            form.setField(screening.getLocation().replace('.', '_'), "Yes");
        }
    }
 
    /**
     * Gets the directors from a Movie object,
     * and concatenates them in a String.
     * @param movie a Movie object
     * @return a String containing director names
     */
    public static String getDirectors(Movie movie) {
        List<Director> directors = movie.getDirectors();
        StringBuffer buf = new StringBuffer();
        for (Director director : directors) {
            buf.append(director.getGivenName());
            buf.append(' ');
            buf.append(director.getName());
            buf.append(',');
            buf.append(' ');
        }
        int i = buf.length();
        if (i > 0)
            buf.delete(i - 2, i);
        return buf.toString();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
 
import part1.chapter02.MovieHistory;
import part1.chapter02.MovieLinks1;
 
public class Concatenate {
 
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/concatenated.pdf";
 
    /**
     * Main method.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        // using previous examples to create PDFs
    	MovieLinks1.main(args);
        MovieHistory.main(args);
        String[] files = { MovieLinks1.RESULT, MovieHistory.RESULT };
        // step 1
        Document document = new Document();
        // step 2
        PdfCopy copy = new PdfCopy(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        PdfReader reader;
        int n;
        // loop over the documents you want to concatenate
        for (int i = 0; i < files.length; i++) {
            reader = new PdfReader(files[i]);
            // loop over the pages in that document
            n = reader.getNumberOfPages();
            for (int page = 0; page < n; ) {
                copy.addPage(copy.getImportedPage(reader, ++page));
            }
            copy.freeReader(reader);
            reader.close();
        }
        // step 5
        document.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
 
import part1.chapter02.MovieHistory;
import part1.chapter02.MovieLinks1;
 
public class ConcatenateStamp {
 
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/concatenated_stamped.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
    	// use old examples to create PDFs
        MovieLinks1.main(args);
        MovieHistory.main(args);
        // step 1
        Document document = new Document();
        // step 2
        PdfCopy copy = new PdfCopy(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        // reader for document 1
        PdfReader reader1 = new PdfReader(MovieLinks1.RESULT);
        int n1 = reader1.getNumberOfPages();
        // reader for document 2
        PdfReader reader2 = new PdfReader(MovieHistory.RESULT);
        int n2 = reader2.getNumberOfPages();
        // initializations
        PdfImportedPage page;
        PdfCopy.PageStamp stamp;
        // Loop over the pages of document 1
        for (int i = 0; i < n1; ) {
            page = copy.getImportedPage(reader1, ++i);
            stamp = copy.createPageStamp(page);
            // add page numbers
            ColumnText.showTextAligned(
                    stamp.getUnderContent(), Element.ALIGN_CENTER,
                    new Phrase(String.format("page %d of %d", i, n1 + n2)),
                    297.5f, 28, 0);
            stamp.alterContents();
            copy.addPage(page);
        }
        // Loop over the pages of document 2
        for (int i = 0; i < n2; ) {
            page = copy.getImportedPage(reader2, ++i);
            stamp = copy.createPageStamp(page);
            // add page numbers
            ColumnText.showTextAligned(
                    stamp.getUnderContent(), Element.ALIGN_CENTER,
                    new Phrase(String.format("page %d of %d", n1 + i, n1 + n2)),
                    297.5f, 28, 0);
            stamp.alterContents();
            copy.addPage(page);
        }
        // step 5
        document.close();
        reader1.close();
        reader2.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
 
import part1.chapter03.MovieTemplates;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
 
public class Burst {
 
    /** Format of the resulting PDF files. */
    public static final String RESULT
        = "results/part2/chapter06/timetable_p%d.pdf";
 
    /**
     * Main method.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// use one of the previous examples to create a PDF
        new MovieTemplates().createPdf(MovieTemplates.RESULT);
        // Create a reader
        PdfReader reader = new PdfReader(MovieTemplates.RESULT);
        // We'll create as many new PDFs as there are pages
        Document document;
        PdfCopy copy;
        // loop over all the pages in the original PDF
        int n = reader.getNumberOfPages();
        for (int i = 0; i < n; ) {
        	// step 1
            document = new Document();
            // step 2
            copy = new PdfCopy(document,
                new FileOutputStream(String.format(RESULT, ++i)));
            // step 3
            document.open();
            // step 4
            copy.addPage(copy.getImportedPage(reader, i));
            // step 5
            document.close();
        }
        reader.close();
    }
 
 
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
 
import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.PojoFactory;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
 
public class DataSheets1 extends FillDataSheet {
 
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/datasheets1.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, SQLException, DocumentException {
        new DataSheets1().createPdf(RESULT);
    }
 
    /**
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws    DocumentException 
     * @throws    IOException
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
    	// step 1
        Document document = new Document();
        // step 2
        PdfCopy copy
            = new PdfCopy(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        addDataSheets(copy);
        // step 5
        document.close();
    }
 
    /**
     * Fills out a data sheet, flattens it, and adds it to a combined PDF.
     * @param copy the PdfCopy instance (can also be PdfSmartCopy)
     * @throws SQLException
     * @throws IOException
     * @throws DocumentException
     */
    public void addDataSheets(PdfCopy copy)
        throws SQLException, IOException, DocumentException {
    	// Create a database connection
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        List<Movie> movies = PojoFactory.getMovies(connection);
        PdfReader reader;
        PdfStamper stamper;
        ByteArrayOutputStream baos;
        // Loop over all the movies and fill out the data sheet
        for (Movie movie : movies) {
            reader = new PdfReader(DATASHEET);
            baos = new ByteArrayOutputStream();
            stamper = new PdfStamper(reader, baos);
            AcroFields fields = stamper.getAcroFields();
            fields.setGenerateAppearances(true);
            fill(fields, movie);
            stamper.setFormFlattening(true);
            stamper.close();
            reader.close();
 
            reader = new PdfReader(baos.toByteArray());
            copy.addPage(copy.getImportedPage(reader, 1));
            copy.freeReader(reader);
            reader.close();
        }
        // Close the database connection
        connection.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfSmartCopy;
 
public class DataSheets2 extends DataSheets1 {
 
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/datasheets2.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, SQLException, DocumentException {
        new DataSheets2().createPdf(RESULT);
    }
 
    /**
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws    DocumentException 
     * @throws    IOException
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
    	// step 1
        Document document = new Document();
        // step 2
        PdfSmartCopy copy
            = new PdfSmartCopy(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        addDataSheets(copy);
        // step 5
        document.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.FileOutputStream;
import java.io.IOException;
 
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopyFields;
import com.itextpdf.text.pdf.PdfReader;
 
public class ConcatenateForms1 {
 
    /** The original PDF file. */
    public static final String DATASHEET
        = "resources/pdfs/datasheet.pdf";
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/concatenated_forms1.pdf";
 
    /**
     * Main method.
     * @param args no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// Create a PdfCopyFields object
        PdfCopyFields copy
            = new PdfCopyFields(new FileOutputStream(RESULT));
        // add a document
        PdfReader reader1 = new PdfReader(DATASHEET);
        copy.addDocument(reader1);
        // add a document
        PdfReader reader2 = new PdfReader(DATASHEET);
        copy.addDocument(reader2);
        // close the PdfCopyFields object
        copy.close();
        reader1.close();
        reader2.close();
    }
}
/*
 * This class is part of the book "iText in Action - 2nd Edition"
 * written by Bruno Lowagie (ISBN: 9781935182610)
 * For more info, go to: http://itextpdf.com/examples/
 * This example only works with the AGPL version of iText.
 */
 
package part2.chapter06;
 
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
 
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfCopyFields;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
 
public class ConcatenateForms2 {
 
    /** The original PDF file. */
    public static final String DATASHEET
        = "resources/pdfs/datasheet.pdf";
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part2/chapter06/concatenated_forms2.pdf";
 
    /**
     * Main method.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// Create a PdfCopyFields object
        PdfCopyFields copy
            = new PdfCopyFields(new FileOutputStream(RESULT));
        // add a document
        PdfReader reader1 = new PdfReader(renameFieldsIn(DATASHEET, 1));
        copy.addDocument(reader1);
        // add a document
        PdfReader reader2 = new PdfReader(renameFieldsIn(DATASHEET, 2));
        copy.addDocument(reader2);
        // Close the PdfCopyFields object
        copy.close();
        reader1.close();
        reader2.close();
    }
 
    /**
     * Renames the fields in an interactive form.
     * @param datasheet the path to the original form
     * @param i a number that needs to be appended to the field names
     * @return a byte[] containing an altered PDF file
     * @throws IOException
     * @throws DocumentException
     */
    private static byte[] renameFieldsIn(String datasheet, int i)
        throws IOException, DocumentException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // Create the stamper
        PdfStamper stamper = new PdfStamper(new PdfReader(datasheet), baos);
        // Get the fields
        AcroFields form = stamper.getAcroFields();
        // Loop over the fields
        Set<String> keys = new HashSet<String>(form.getFields().keySet());
        for (String key : keys) {
            // rename the fields
            form.renameField(key, String.format("%s_%d", key, i));
        }
        // close the stamper
        stamper.close();
        return baos.toByteArray();
    }
}
File nameRaw URLUpdated
PageInformation.javaPageInformation.java2015-10-10 2:46 pm
MemoryInfo.javaMemoryInfo.java2015-10-10 2:46 pm
SelectPages.javaSelectPages.java2015-10-10 2:46 pm
ImportingPages1.javaImportingPages1.java2015-10-10 2:46 pm
ImportingPages2.javaImportingPages2.java2015-10-10 2:46 pm
Layers.javaLayers.java2015-10-10 2:46 pm
Superimposing.javaSuperimposing.java2015-10-10 2:46 pm
Stationery.javaStationery.java2015-10-10 2:46 pm
NUpTool.javaNUpTool.java2015-10-10 2:46 pm
TilingHero.javaTilingHero.java2015-10-10 2:46 pm
StampText.javaStampText.java2015-10-10 2:46 pm
TwoPasses.javaTwoPasses.java2015-10-10 2:46 pm
StampStationery.javaStampStationery.java2015-10-10 2:46 pm
InsertPages.javaInsertPages.java2015-10-10 2:46 pm
FormInformation.javaFormInformation.java2015-10-10 2:46 pm
FillDataSheet.javaFillDataSheet.java2015-10-10 2:46 pm
Concatenate.javaConcatenate.java2015-10-10 2:46 pm
ConcatenateStamp.javaConcatenateStamp.java2015-10-10 2:46 pm
Burst.javaBurst.java2015-10-10 2:46 pm
DataSheets1.javaDataSheets1.java2015-10-10 2:46 pm
DataSheets2.javaDataSheets2.java2015-10-10 2:46 pm
ConcatenateForms1.javaConcatenateForms1.java2015-10-10 2:46 pm
ConcatenateForms2.javaConcatenateForms2.java2015-10-10 2:46 pm
Resources: 
File nameRaw URLUpdated
datasheet.odtdatasheet.odt2015-10-24 2:11 am
datasheet.pdfdatasheet.pdf2015-10-24 2:11 am
C# port: 
File nameRaw URLUpdated
PageInformation.csPageInformation.cs2015-10-10 2:47 pm
MemoryInfo.csMemoryInfo.cs2015-10-10 2:47 pm
SelectPages.csSelectPages.cs2015-10-10 2:47 pm
ImportingPages1.csImportingPages1.cs2015-10-10 2:47 pm
ImportingPages2.csImportingPages2.cs2015-10-10 2:47 pm
Layers.csLayers.cs2015-10-10 2:47 pm
Superimposing.csSuperimposing.cs2015-10-10 2:47 pm
Stationery.csStationery.cs2015-10-10 2:47 pm
NUpTool.csNUpTool.cs2015-10-10 2:47 pm
TilingHero.csTilingHero.cs2015-10-10 2:47 pm
StampText.csStampText.cs2015-10-10 2:47 pm
TwoPasses.csTwoPasses.cs2015-10-10 2:47 pm
InsertPages.csInsertPages.cs2015-10-10 2:47 pm
FormInformation.csFormInformation.cs2015-10-10 2:47 pm
FillDataSheet.csFillDataSheet.cs2015-10-10 2:47 pm
Concatenate.csConcatenate.cs2015-10-10 2:47 pm
ConcatenateStamp.csConcatenateStamp.cs2015-10-10 2:47 pm
Burst.csBurst.cs2015-10-10 2:47 pm
DataSheets1.csDataSheets1.cs2015-10-10 2:47 pm
DataSheets2.csDataSheets2.cs2015-10-10 2:47 pm
ConcatenateForms1.csConcatenateForms1.cs2015-10-10 2:47 pm
ConcatenateForms2.csConcatenateForms2.cs2015-10-10 2:47 pm
StampStationery.csStampStationery.cs2015-10-10 2:47 pm