Chapter 2: Using iText's basic building blocks

This is a code example of iText PDF, discover more.

10th October 2015
admin-marketing

Switch code for this example

DatabaseTest.java
/*
 * 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 part1.chapter02;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;

/**
 * We'll test our hsqldb database with this example
 */
public class DatabaseTest {
    
    /** The output of this database test: a text file with a list of countries. */
    public static final String RESULT = "results/part1/chapter02/countries.txt";
    
    /**
     * Writes the names of the countries that are in our database
     * @param    args    no arguments needed 
     * @throws FileNotFoundException 
     */
    public static void main(String[] args)
        throws SQLException, UnsupportedEncodingException, FileNotFoundException {
    	// no PDF, just a text file
        PrintStream out = new PrintStream(new FileOutputStream(RESULT));
        // Make the connection to the database
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        // create the statement
        Statement stm = connection.createStatement();
        // execute the query
        ResultSet rs = stm.executeQuery("SELECT country FROM film_country ORDER BY country");
        // loop over the results
        while (rs.next()) {
        	// write a country to the text file
            out.println(rs.getString("country"));
        }
        // close the statement
        stm.close();
        // close the database connection
        connection.close();
        // flush and close the print stream
        out.flush();
        out.close();
    }
}
CountryChunks.java
/*
 * 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 part1.chapter02;

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.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.BaseColor;

/**
 * Writes a list of countries to a PDF file.
 */
public class CountryChunks {

    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part1/chapter02/country_chunks.pdf";

    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException
     * @throws IOException
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new CountryChunks().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
        PdfWriter.getInstance(document, new FileOutputStream(filename))
            .setInitialLeading(16);
        // step 3
        document.open();
        // step 4
        // database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT country, id FROM film_country ORDER BY country");
        // add the ID in another font
        Font font = new Font(FontFamily.HELVETICA, 6, Font.BOLD, BaseColor.WHITE);
        while (rs.next()) {
        	// add a country to the document as a Chunk
            document.add(new Chunk(rs.getString("country")));
            document.add(new Chunk(" "));
            Chunk id = new Chunk(rs.getString("id"), font);
            // with a background color
            id.setBackground(BaseColor.BLACK, 1f, 0.5f, 1f, 1.5f);
            // and a text rise
            id.setTextRise(6);
            document.add(id);
            document.add(Chunk.NEWLINE);
        }
        stm.close();
        connection.close();
        // step 5
        document.close();
    }
}
DirectorPhrases1.java
/*
 * 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 part1.chapter02;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
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.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.PdfWriter;

/**
 * Writes a list of directors to a PDF file.
 */
public class DirectorPhrases1 {
    
    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/director_phrases_1.pdf";

    /** A font that will be used in our PDF. */
    public static final Font BOLD_UNDERLINED =
        new Font(FontFamily.TIMES_ROMAN, 12, Font.BOLD | Font.UNDERLINE);
    /** A font that will be used in our PDF. */
    public static final Font NORMAL =
        new Font(FontFamily.TIMES_ROMAN, 12);
    
    /**
     * Creates a Phrase with the name and given name of a director using different fonts.
     * @param    rs    the ResultSet containing director records.
     */
    public Phrase createDirectorPhrase(ResultSet rs)
        throws UnsupportedEncodingException, SQLException {
        Phrase director = new Phrase();
        director.add(
            new Chunk(new String(rs.getBytes("name"), "UTF-8"), BOLD_UNDERLINED));
        director.add(new Chunk(",", BOLD_UNDERLINED));
        director.add(new Chunk(" ", NORMAL));
        director.add(
            new Chunk(new String(rs.getBytes("given_name"), "UTF-8"), NORMAL));
        return director;
    }
    
    /**
     * Creates a PDF file with director names.
     * @param    filename    the name of the PDF file that needs to be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
    	// step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        // create the database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT name, given_name FROM film_director ORDER BY name, given_name");
        // loop over the results
        while (rs.next()) {
            document.add(createDirectorPhrase(rs));
            document.add(Chunk.NEWLINE);
        }
        // close the statement and database connection
        stm.close();
        connection.close();
        // step 5
        document.close();
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new DirectorPhrases1().createPdf(RESULT);
    }
}
DirectorPhrases2.java
/*
 * 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 part1.chapter02;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.itextpdf.text.Chunk;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.BaseFont;

/**
 * Writes a list of directors to a PDF file.
 */
public class DirectorPhrases2 extends DirectorPhrases1 {
    
    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/director_phrases_2.pdf";

    /** A font that will be used in our PDF. */
    public static final Font BOLD;
    /** A font that will be used in our PDF. */
    public static final Font NORMAL;
    
    static {
        BaseFont timesbd = null;
        BaseFont times = null;
        try {
            // create a font that will be embedded
            timesbd = BaseFont.createFont(
                "c:/windows/fonts/timesbd.ttf", BaseFont.WINANSI, BaseFont.EMBEDDED);
            // create a font that will be embedded
            times = BaseFont.createFont(
                "c:/windows/fonts/times.ttf", BaseFont.WINANSI, BaseFont.EMBEDDED);
        } catch (DocumentException e) {
            e.printStackTrace();
            System.exit(1);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
        BOLD = new Font(timesbd, 12);
        NORMAL = new Font(times, 12);
    }
    
    /**
     * Creates a Phrase with the name and given name of a director using different fonts.
     * @param    rs    the ResultSet containing director records.
     */
    public Phrase createDirectorPhrase(ResultSet rs)
        throws UnsupportedEncodingException, SQLException {
        Phrase director = new Phrase();
        Chunk name = new Chunk(new String(rs.getBytes("name"), "UTF-8"), BOLD);
        name.setUnderline(0.2f, -2f);
        director.add(name);
        director.add(new Chunk(",", BOLD));
        director.add(new Chunk(" ", NORMAL));
        director.add(
            new Chunk(new String(rs.getBytes("given_name"), "UTF-8"), NORMAL));
        director.setLeading(24);
        return director;
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new DirectorPhrases2().createPdf(RESULT);
    }
}
MovieTitles.java
/*
 * 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 part1.chapter02;

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.PojoFactory;
import com.lowagie.filmfestival.Movie;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

/**
 * Writes a list of movies titles to a PDF file.
 */
public class MovieTitles {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/movie_titles.pdf";
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args) throws IOException, DocumentException, SQLException {
    	// Create a database connection
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        List movies = PojoFactory.getMovies(connection);
        for (Movie movie : movies) {
            document.add(new Paragraph(movie.getTitle()));
        }
        // step 5
        document.close();
        // Close the database connection
        connection.close();
    }
}
MovieParagraphs1.java
/*
 * 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 part1.chapter02;

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.Country;
import com.lowagie.filmfestival.Director;
import com.lowagie.filmfestival.FilmFonts;
import com.lowagie.filmfestival.PojoToElementFactory;
import com.lowagie.filmfestival.PojoFactory;
import com.lowagie.filmfestival.Movie;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfWriter;

/**
 * Writes a list of movies titles to a PDF file.
 */
public class MovieParagraphs1 {

    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part1/chapter02/movie_paragraphs_1.pdf";
    
    /**
     * Creates a Paragraph containing information about a movie.
     * @param    movie    the movie for which you want to create a Paragraph
     */
    public Paragraph createMovieInformation(Movie movie) {
        Paragraph p = new Paragraph();
        p.setFont(FilmFonts.NORMAL);
        p.add(new Phrase("Title: ", FilmFonts.BOLDITALIC));
        p.add(PojoToElementFactory.getMovieTitlePhrase(movie));
        p.add(" ");
        if (movie.getOriginalTitle() != null) {
            p.add(new Phrase("Original title: ", FilmFonts.BOLDITALIC));
            p.add(PojoToElementFactory.getOriginalTitlePhrase(movie));
            p.add(" ");
        }
        p.add(new Phrase("Country: ", FilmFonts.BOLDITALIC));
        for (Country country : movie.getCountries()) {
            p.add(PojoToElementFactory.getCountryPhrase(country));
            p.add(" ");
        }
        p.add(new Phrase("Director: ", FilmFonts.BOLDITALIC));
        for (Director director : movie.getDirectors()) {
            p.add(PojoToElementFactory.getDirectorPhrase(director));
            p.add(" ");
        }
        p.add(createYearAndDuration(movie));
        return p;
    }
    
    /**
     * Creates a Paragraph containing information about the year
     * and the duration of a movie.
     * @param    movie    the movie for which you want to create a Paragraph
     */
    public Paragraph createYearAndDuration(Movie movie) {
        Paragraph info = new Paragraph();
        info.setFont(FilmFonts.NORMAL);
        info.add(new Chunk("Year: ", FilmFonts.BOLDITALIC));
        info.add(new Chunk(String.valueOf(movie.getYear()), FilmFonts.NORMAL));
        info.add(new Chunk(" Duration: ", FilmFonts.BOLDITALIC));
        info.add(new Chunk(String.valueOf(movie.getDuration()), FilmFonts.NORMAL));
        info.add(new Chunk(" minutes", FilmFonts.NORMAL));
        return info;
    }
    
    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
        // Create a database connection
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        List movies = PojoFactory.getMovies(connection);
        for (Movie movie : movies) {
            Paragraph p = createMovieInformation(movie);
            p.setAlignment(Element.ALIGN_JUSTIFIED);
            p.setIndentationLeft(18);
            p.setFirstLineIndent(-18);
            document.add(p);
        }
        // step 5
        document.close();
        // Close the database connection
        connection.close();
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new MovieParagraphs1().createPdf(RESULT);
    }
}
MovieParagraphs2.java
/*
 * 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 part1.chapter02;

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.Country;
import com.lowagie.filmfestival.Director;
import com.lowagie.filmfestival.FilmFonts;
import com.lowagie.filmfestival.PojoFactory;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.PojoToElementFactory;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

public class MovieParagraphs2 extends MovieParagraphs1 {

    public static final String RESULT = "results/part1/chapter02/movie_paragraphs_2.pdf";
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new MovieParagraphs2().createPdf(RESULT);
    }
    
    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
    	// Create a database connection
        DatabaseConnection connection = new HsqldbConnection("filmfestival");    
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        List movies = PojoFactory.getMovies(connection);
        for (Movie movie : movies) {
            // Create a paragraph with the title
            Paragraph title = new Paragraph(
                PojoToElementFactory.getMovieTitlePhrase(movie));
            title.setAlignment(Element.ALIGN_LEFT);
            document.add(title);
            // Add the original title next to it using a dirty hack
            if (movie.getOriginalTitle() != null) {
                Paragraph dummy = new Paragraph("\u00a0", FilmFonts.NORMAL);
                dummy.setLeading(-18);
                document.add(dummy);
                Paragraph originalTitle = new Paragraph(
                    PojoToElementFactory.getOriginalTitlePhrase(movie));
                originalTitle.setAlignment(Element.ALIGN_RIGHT);
                document.add(originalTitle);
            }
            // Info about the director
            Paragraph director;
            float indent = 20;
            // Loop over the directors
            for (Director pojo : movie.getDirectors()) {
                director = new Paragraph(
                    PojoToElementFactory.getDirectorPhrase(pojo));
                director.setIndentationLeft(indent);
                document.add(director);
                indent += 20;
            }
            // Info about the country
            Paragraph country;
            indent = 20;
            // Loop over the countries
            for (Country pojo : movie.getCountries()) {
                country = new Paragraph(
                    PojoToElementFactory.getCountryPhrase(pojo));
                country.setAlignment(Element.ALIGN_RIGHT);
                country.setIndentationRight(indent);
                document.add(country);
                indent += 20;
            }
            // Extra info about the movie
            Paragraph info = createYearAndDuration(movie);
            info.setAlignment(Element.ALIGN_CENTER);
            info.setSpacingAfter(36);
            document.add(info);
        }
        // step 5
        document.close();
        // Close the database connection
        connection.close();
    }
}
PipeSplitCharacter.java
/*
 * 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 part1.chapter02;

import com.itextpdf.text.SplitCharacter;
import com.itextpdf.text.pdf.PdfChunk;

/**
 * Implementation of the SplitCharacter interface.
 * Use an instance of this class with Chunk.setSplitCharacter();
 */
public class PipeSplitCharacter implements SplitCharacter {
	
    /**
     * @see com.itextpdf.text.SplitCharacter#isSplitCharacter(int, int, int, char[],
     *      com.itextpdf.text.pdf.PdfChunk[])
     */
    public boolean isSplitCharacter(int start, int current, int end, char[] cc,
            PdfChunk[] ck) {
        char c;
        if (ck == null)
            c = cc[current];
        else
            c = (char)ck[Math.min(current, ck.length - 1)]
                    .getUnicodeEquivalent(cc[current]);
        return (c == '|' || c <= ' ' || c == '-');
    }

}
MovieChain.java
/*
 * 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 part1.chapter02;

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.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.HyphenationAuto;
import com.itextpdf.text.pdf.PdfWriter;

/**
 * Writes a list of directors to a PDF file.
 */
public class MovieChain {
    
    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/kubrick.pdf";
    
    /**
     * Creates a PDF file with director names.
     * @param    filename    the name of the PDF file that needs to be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {

        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        List kubrick = PojoFactory.getMovies(connection, 1);
        connection.close();
        // step 1
        Document document = new Document(new Rectangle(240, 240), 10, 10, 10, 10);
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        // create a long Stringbuffer with movie titles
        StringBuffer buf1 = new StringBuffer();
        for (Movie movie : kubrick) {
            // replace spaces with non-breaking spaces
            buf1.append(movie.getMovieTitle().replace(' ', '\u00a0'));
            // use pipe as separator
            buf1.append('|');
        }
        // Create a first chunk
        Chunk chunk1 = new Chunk(buf1.toString());
        // wrap the chunk in a paragraph and add it to the document
        Paragraph paragraph = new Paragraph("A:\u00a0");
        paragraph.add(chunk1);
        paragraph.setAlignment(Element.ALIGN_JUSTIFIED);
        document.add(paragraph);
        document.add(Chunk.NEWLINE);
        // define the pipe character as split character
        chunk1.setSplitCharacter(new PipeSplitCharacter());
        // wrap the chunk in a second paragraph and add it
        paragraph = new Paragraph("B:\u00a0");
        paragraph.add(chunk1);
        paragraph.setAlignment(Element.ALIGN_JUSTIFIED);
        document.add(paragraph);
        document.add(Chunk.NEWLINE);

        // create a new StringBuffer with movie titles
        StringBuffer buf2 = new StringBuffer();
        for (Movie movie : kubrick) {
            buf2.append(movie.getMovieTitle());
            buf2.append('|');
        }
        // Create a second chunk 
        Chunk chunk2 = new Chunk(buf2.toString());
        // wrap the chunk in a paragraph and add it to the document
        paragraph = new Paragraph("C:\u00a0");
        paragraph.add(chunk2);
        paragraph.setAlignment(Element.ALIGN_JUSTIFIED);
        document.add(paragraph);
        document.newPage();
        // define hyphenation for the chunk
        chunk2.setHyphenation(new HyphenationAuto("en", "US", 2, 2));
        // wrap the second chunk in a second paragraph and add it
        paragraph = new Paragraph("D:\u00a0");
        paragraph.add(chunk2);
        paragraph.setAlignment(Element.ALIGN_JUSTIFIED);
        document.add(paragraph);
        
        // go to a new page
        document.newPage();
        // define a new space/char ratio
        writer.setSpaceCharRatio(PdfWriter.NO_SPACE_CHAR_RATIO);
        // wrap the second chunk in a third paragraph and add it
        paragraph = new Paragraph("E:\u00a0");
        paragraph.add(chunk2);
        paragraph.setAlignment(Element.ALIGN_JUSTIFIED);
        document.add(paragraph);
        // step 5
        document.close();
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new MovieChain().createPdf(RESULT);
    }
}
MovieLists1.java
/*
 * 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 part1.chapter02;

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.lowagie.filmfestival.Director;
import com.lowagie.filmfestival.FilmFonts;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.PojoFactory;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.List;
import com.itextpdf.text.ListItem;
import com.itextpdf.text.pdf.PdfWriter;

public class MovieLists1 {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/movie_lists_1.pdf";
    
    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        // Create database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT DISTINCT mc.country_id, c.country, count(*) AS c "
            + "FROM film_country c, film_movie_country mc "
            + "WHERE c.id = mc.country_id "
            + "GROUP BY mc.country_id, country ORDER BY c DESC");
        // Create a new list
        List list = new List(List.ORDERED);
        // loop over the countries
        while (rs.next()) {
        	// create a list item for the country
            ListItem item = new ListItem(
                String.format("%s: %d movies",
                    rs.getString("country"), rs.getInt("c")),
                FilmFonts.BOLDITALIC);
            // create a movie list for each country
            List movielist = new List(List.ORDERED, List.ALPHABETICAL);
            movielist.setLowercase(List.LOWERCASE);
            for(Movie movie :
                PojoFactory.getMovies(connection, rs.getString("country_id"))) {
                ListItem movieitem = new ListItem(movie.getMovieTitle());
                List directorlist = new List(List.UNORDERED);
                for (Director director : movie.getDirectors()) {
                    directorlist.add(
                        String.format("%s, %s",
                            director.getName(), director.getGivenName()));
                }
                movieitem.add(directorlist);
                movielist.add(movieitem);
            }
            item.add(movielist);
            list.add(item);
        }
        document.add(list);
        // close the statement and the database connection
        stm.close();
        connection.close();
        // step 4
        document.close();
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args) throws IOException, DocumentException, SQLException {
        new MovieLists1().createPdf(RESULT);
    }
}
MovieLists2.java
/*
 * 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 part1.chapter02;

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.lowagie.filmfestival.Director;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.PojoFactory;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.List;
import com.itextpdf.text.ListItem;
import com.itextpdf.text.pdf.PdfWriter;

public class MovieLists2 {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/movie_lists_2.pdf";
    
    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        // Create a database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT DISTINCT mc.country_id, c.country, count(*) AS c "
            + "FROM film_country c, film_movie_country mc WHERE c.id = mc.country_id "
            + "GROUP BY mc.country_id, country ORDER BY c DESC");
        // Create a list
        List list = new List();
        list.setAutoindent(false);
        list.setSymbolIndent(36);
        // Loop over the countries
        while (rs.next()) {
            // Create a list item for a country
            ListItem item = new ListItem(
               String.format("%s: %d movies", rs.getString("country"), rs.getInt("c")));
            item.setListSymbol(new Chunk(rs.getString("country_id")));
            // Create a list for the movies produced in the current country
            List movielist = new List(List.ORDERED, List.ALPHABETICAL);
            movielist.setAlignindent(false);
            for(Movie movie :
                PojoFactory.getMovies(connection, rs.getString("country_id"))) {
                ListItem movieitem = new ListItem(movie.getMovieTitle());
                List directorlist = new List(List.ORDERED);
                directorlist.setPreSymbol("Director ");
                directorlist.setPostSymbol(": ");
                for (Director director : movie.getDirectors()) {
                    directorlist.add(
                        String.format("%s, %s", director.getName(), director.getGivenName()));
                }
                movieitem.add(directorlist);
                movielist.add(movieitem);
            }
            item.add(movielist);
            list.add(item);
        }
        document.add(list);
        // Close the statement and database connection
        stm.close();
        connection.close();
        // step 5
        document.close();
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args) throws IOException, DocumentException, SQLException {
        new MovieLists2().createPdf(RESULT);
    }
}
MovieLists3.java
/*
 * 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 part1.chapter02;

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.lowagie.filmfestival.Director;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.PojoFactory;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.GreekList;
import com.itextpdf.text.List;
import com.itextpdf.text.ListItem;
import com.itextpdf.text.RomanList;
import com.itextpdf.text.ZapfDingbatsNumberList;
import com.itextpdf.text.pdf.PdfWriter;

public class MovieLists3 {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/movie_lists_3.pdf";
    
    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        // Create database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT DISTINCT mc.country_id, c.country, count(*) AS c "
            + "FROM film_country c, film_movie_country mc WHERE c.id = mc.country_id "
            + "GROUP BY mc.country_id, country ORDER BY c DESC");
        // Create a list for the countries
        List list = new RomanList();
        // Loop over the countries
        while (rs.next()) {
            // Create a list item for the country
            ListItem item = new ListItem(
               String.format("%s: %d movies", rs.getString("country"), rs.getInt("c")));
            // Create a list for the movies
            List movielist = new GreekList();
            movielist.setLowercase(List.LOWERCASE);
            // Loop over the movies
            for(Movie movie :
                PojoFactory.getMovies(connection, rs.getString("country_id"))) {
                ListItem movieitem = new ListItem(movie.getMovieTitle());
                // Create a list for the directors
                List directorlist = new ZapfDingbatsNumberList(0);
                // Loop over the directors
                for (Director director : movie.getDirectors()) {
                    directorlist.add(String.format("%s, %s",
                       director.getName(), director.getGivenName()));
                }
                movieitem.add(directorlist);
                movielist.add(movieitem);
            }
            item.add(movielist);
            list.add(item);
        }
        document.add(list);
        // Close the statement and the database connection
        stm.close();
        connection.close();
        // step 5
        document.close();
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args) throws IOException, DocumentException, SQLException {
        new MovieLists3().createPdf(RESULT);
    }
}
MovieLists4.java
/*
 * 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 part1.chapter02;

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.lowagie.filmfestival.Director;
import com.lowagie.filmfestival.FilmFonts;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.PojoFactory;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.List;
import com.itextpdf.text.ListItem;
import com.itextpdf.text.ZapfDingbatsList;
import com.itextpdf.text.pdf.PdfWriter;

public class MovieLists4 {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/movie_lists_4.pdf";
    
    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        // Create the database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT DISTINCT mc.country_id, c.country, count(*) AS c "
            + "FROM film_country c, film_movie_country mc "
            + "WHERE c.id = mc.country_id "
            + "GROUP BY mc.country_id, country ORDER BY c DESC");
        // Create a list for the countries
        List list = new List(List.ORDERED);
        list.setFirst(9);
        // Loop over the countries
        while (rs.next()) {
            // Create a list item for a country
            ListItem item = new ListItem(String.format("%s: %d movies",
                rs.getString("country"), rs.getInt("c")));
            // Create a list for the movies
            List movielist = new List();
            movielist.setListSymbol(new Chunk("Movie: ", FilmFonts.BOLD));
            for(Movie movie :
                PojoFactory.getMovies(connection, rs.getString("country_id"))) {
                ListItem movieitem = new ListItem(movie.getMovieTitle());
                // Create a list for the directors
                List directorlist = new ZapfDingbatsList(42);
                for (Director director : movie.getDirectors()) {
                    directorlist.add(String.format("%s, %s",
                        director.getName(), director.getGivenName()));
                }
                movieitem.add(directorlist);
                movielist.add(movieitem);
            }
            item.add(movielist);
            list.add(item);
        }
        document.add(list);
        // Close the statement and database connection
        stm.close();
        connection.close();
        // step 5
        document.close();
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args) throws IOException, DocumentException, SQLException {
        new MovieLists4().createPdf(RESULT);
    }
}
PositionedArrow.java
/*
 * 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 part1.chapter02;

import java.io.IOException;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.draw.VerticalPositionMark;

/**
 * Subclass of VerticalPositionMark that draws an arrow in the left
 * or right margin.
 */
public class PositionedArrow extends VerticalPositionMark {

    /** Indicates if the arrow needs to be drawn to the left. */
    protected boolean left;
    
    /** Thee font that will be used to draw the arrow. */
    protected BaseFont zapfdingbats;
    
    /** An arrow pointing to the right will be added on the left. */
    public static final PositionedArrow LEFT = new PositionedArrow(true);
    /** An arrow pointing to the left will be added on the right. */
    public static final PositionedArrow RIGHT = new PositionedArrow(false);
    
    /**
     * Constructs a positioned Arrow mark.
     * @param    left    if true, an arrow will be drawn on the left;
     * otherwise, it will be drawn on the right.
     * @throws IOException 
     * @throws DocumentException 
     */
    public PositionedArrow(boolean left) {
        this.left = left;
        try {
            zapfdingbats = BaseFont.createFont(
                BaseFont.ZAPFDINGBATS, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED);
        }
        catch(DocumentException de) {
            zapfdingbats = null;
        }
        catch(IOException ioe) {
            zapfdingbats = null;
        }
    }
    
    /**
     * Draws a character representing an arrow at the current position.
     * @see com.itextpdf.text.pdf.draw.VerticalPositionMark#draw(
     *      com.itextpdf.text.pdf.PdfContentByte, float, float, float, float, float)
     */
    public void draw(PdfContentByte canvas, float llx, float lly, float urx, float ury, float y) {
        canvas.beginText();
        canvas.setFontAndSize(zapfdingbats, 12);
        if (left) {
            canvas.showTextAligned(Element.ALIGN_CENTER,
                String.valueOf((char)220), llx - 10, y, 0);
        }
        else {
            canvas.showTextAligned(Element.ALIGN_CENTER,
                String.valueOf((char)220), urx + 10, y + 8, 180);
        }
        canvas.endText();
    }
}
StarSeparator.java
/*
 * 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 part1.chapter02;

import java.io.IOException;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.draw.DrawInterface;

public class StarSeparator implements DrawInterface {
    
    /** The font that will be used to draw the arrow. */
    protected BaseFont bf;
    
    public static final StarSeparator LINE = new StarSeparator();
    
    /**
     * Constructs a positioned Arrow mark.
     * @param    left    if true, an arrow will be drawn on the left;
     * otherwise, it will be drawn on the right.
     * @throws IOException 
     * @throws DocumentException 
     */
    public StarSeparator() {
        try {
            bf = BaseFont.createFont();
        } catch (DocumentException e) {
            bf = null;
        } catch (IOException e) {
            bf = null;
        }
    }
    
    /**
     * Draws three stars to separate two paragraphs.
     * @see com.itextpdf.text.pdf.draw.DrawInterface#draw(
     * com.itextpdf.text.pdf.PdfContentByte, float, float, float, float, float)
     */
    public void draw(PdfContentByte canvas,
        float llx, float lly, float urx, float ury, float y) {
        float middle = (llx + urx) / 2;
        canvas.beginText();
        canvas.setFontAndSize(bf, 10);
        canvas.showTextAligned(Element.ALIGN_CENTER, "*", middle, y, 0);
        canvas.showTextAligned(Element.ALIGN_CENTER, "*  *", middle, y -10, 0);
        canvas.endText();
    }

}
DirectorOverview1.java
/*
 * 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 part1.chapter02;

import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.TreeSet;

import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.Director;
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.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.LineSeparator;

public class DirectorOverview1 {
    
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part1/chapter02/director_overview_1.pdf";

    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
        // step 1
    	Document document = new Document();
        // step 2
    	PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
    	document.open();
        // step 4
    	// database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT DISTINCT d.id, d.name, d.given_name, count(*) AS c "
            + "FROM film_director d, film_movie_director md "
            + "WHERE d.id = md.director_id "
            + "GROUP BY d.id, d.name, d.given_name ORDER BY name");
        Director director;
        // creating separators
        LineSeparator line
            = new LineSeparator(1, 100, null, Element.ALIGN_CENTER, -2);
        Paragraph stars = new Paragraph(20);
        stars.add(new Chunk(StarSeparator.LINE));
        stars.setSpacingAfter(30);
        // looping over the directors
        while (rs.next()) {
            // get the director object and use it in a Paragraph
            director = PojoFactory.getDirector(rs);
            Paragraph p = new Paragraph(
                PojoToElementFactory.getDirectorPhrase(director));
            // if there are more than 2 movies for this director
            // an arrow is added to the left
            if (rs.getInt("c") > 2)
                p.add(PositionedArrow.LEFT);
            p.add(line);
            // add the paragraph with the arrow to the document
            document.add(p);
            
            // Get the movies of the directory, ordered by year
            TreeSet movies = new TreeSet(
                new MovieComparator(MovieComparator.BY_YEAR));
            movies.addAll(PojoFactory.getMovies(connection, rs.getInt("id")));
            // loop over the movies
            for (Movie movie : movies) {
                p = new Paragraph(movie.getMovieTitle());
                p.add(": ");
                p.add(new Chunk(String.valueOf(movie.getYear())));
                if (movie.getYear() > 1999)
                    p.add(PositionedArrow.RIGHT);
                document.add(p);
            }
            // add a star separator after the director info is added
            document.add(stars);
        }
        // step 5
        document.close();
        connection.close();
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new DirectorOverview1().createPdf(RESULT);
    }
}
DirectorOverview2.java
/*
 * 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 part1.chapter02;

import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.TreeSet;

import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.Director;
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.List;
import com.itextpdf.text.ListItem;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.DottedLineSeparator;
import com.itextpdf.text.pdf.draw.VerticalPositionMark;

public class DirectorOverview2 {

    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part1/chapter02/director_overview_2.pdf";

    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        // create database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT DISTINCT d.id, d.name, d.given_name, count(*) AS c "
            + "FROM film_director d, film_movie_director md WHERE d.id = md.director_id "
            + "GROUP BY d.id, d.name, d.given_name ORDER BY c DESC");
        Director director;
        // loop over the directors
        while (rs.next()) {
            // create a paragraph for the director
            director = PojoFactory.getDirector(rs);
            Paragraph p = new Paragraph(PojoToElementFactory.getDirectorPhrase(director));
            // add a dotted line separator
            p.add(new Chunk(new DottedLineSeparator()));
            // adds the number of movies of this director
            p.add(String.format("movies: %d", rs.getInt("c")));
            document.add(p);
            // Creates a list
            List list = new List(List.ORDERED);
            list.setIndentationLeft(36);
            list.setIndentationRight(36);
            // Gets the movies of the current director
            TreeSet movies =
                new TreeSet(new MovieComparator(MovieComparator.BY_YEAR));
            movies.addAll(PojoFactory.getMovies(connection, rs.getInt("id")));
            ListItem movieitem;
            // loops over the movies
            for (Movie movie : movies) {
            	// creates a list item with a movie title
                movieitem = new ListItem(movie.getMovieTitle());
                // adds a vertical position mark as a separator
                movieitem.add(new Chunk(new VerticalPositionMark()));
                // adds the year the movie was produced
                movieitem.add(new Chunk(String.valueOf(movie.getYear())));
                // add an arrow to the right if the movie dates from 2000 or later
                if (movie.getYear() > 1999) {
                    movieitem.add(PositionedArrow.RIGHT);
                }
                // add the list item to the list
                list.add(movieitem);
            }
            // add the list to the document
            document.add(list);
        }
        // step 5
        document.close();
        connection.close();
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new DirectorOverview2().createPdf(RESULT);
    }
}
DirectorOverview3.java
/*
 * 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 part1.chapter02;

import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.TreeSet;

import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.Director;
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.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.pdf.draw.DottedLineSeparator;
import com.itextpdf.text.pdf.draw.LineSeparator;
import com.itextpdf.text.pdf.draw.VerticalPositionMark;

public class DirectorOverview3 {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/director_overview_3.pdf";

    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
    	// step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        // creates the database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT DISTINCT d.id, d.name, d.given_name, count(*) AS c "
            + "FROM film_director d, film_movie_director md "
            + "WHERE d.id = md.director_id "
            + "GROUP BY d.id, d.name, d.given_name ORDER BY c DESC");
        Director director;
        // creates line separators
        Chunk CONNECT = new Chunk(
            new LineSeparator(0.5f, 95, BaseColor.BLUE, Element.ALIGN_CENTER, 3.5f));
        LineSeparator UNDERLINE =
            new LineSeparator(1, 100, null, Element.ALIGN_CENTER, -2);
        // creates tabs
        Chunk tab1 = new Chunk(new VerticalPositionMark(), 200, true);
        Chunk tab2 = new Chunk(new VerticalPositionMark(), 350, true);
        Chunk tab3 = new Chunk(new DottedLineSeparator(), 450, true);
        // loops over the directors
        while (rs.next()) {
            // creates a paragraph with the director name
            director = PojoFactory.getDirector(rs);
            Paragraph p = new Paragraph(PojoToElementFactory.getDirectorPhrase(director));
            // adds a separator
            p.add(CONNECT);
            // adds more info about the director
            p.add(String.format("movies: %d", rs.getInt("c")));
            // adds a separator
            p.add(UNDERLINE);
            // adds the paragraph to the document
            document.add(p);
            // gets all the movies of the current director
            TreeSet movies
                = new TreeSet(new MovieComparator(MovieComparator.BY_YEAR));
            movies.addAll(PojoFactory.getMovies(connection, rs.getInt("id")));
            // loop over the movies
            for (Movie movie : movies) {
            	// create a Paragraph with the movie title
                p = new Paragraph(movie.getMovieTitle());
                // insert a tab
                p.add(new Chunk(tab1));
                // add the origina title
                if (movie.getOriginalTitle() != null)
                    p.add(new Chunk(movie.getOriginalTitle()));
                // insert a tab
                p.add(new Chunk(tab2));
                // add the run length of the movie
                p.add(new Chunk(String.format("%d minutes", movie.getDuration())));
                // insert a tab
                p.add(new Chunk(tab3));
                // add the production year of the movie
                p.add(new Chunk(String.valueOf(movie.getYear())));
                // add the paragraph to the document
                document.add(p);
            }
            document.add(Chunk.NEWLINE);
        }
        // step 5
        document.close();
        connection.close();
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new DirectorOverview3().createPdf(RESULT);
    }
}
MovieLinks1.java
/*
 * 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 part1.chapter02;

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.lowagie.filmfestival.FilmFonts;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.PojoFactory;
import com.itextpdf.text.Anchor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

public class MovieLinks1 {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/movie_links_1.pdf";
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new MovieLinks1().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
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        // Create database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT DISTINCT mc.country_id, c.country, count(*) AS c "
            + "FROM film_country c, film_movie_country mc "
            + "WHERE c.id = mc.country_id "
            + "GROUP BY mc.country_id, country ORDER BY c DESC");
        Anchor imdb;
        // loop over the countries
        while (rs.next()) {
            Paragraph country = new Paragraph();
            // the name of the country will be a destination
            Anchor dest = new Anchor(rs.getString("country"), FilmFonts.BOLD);
            dest.setName(rs.getString("country_id"));
            country.add(dest);
            country.add(String.format(": %d movies", rs.getInt("c")));
            document.add(country);
            // loop over the movies
            for(Movie movie :
                PojoFactory.getMovies(connection, rs.getString("country_id"))) {
            	// the movie title will be an external link
                imdb = new Anchor(movie.getMovieTitle());
                imdb.setReference(
                    String.format("http://www.imdb.com/title/tt%s/", movie.getImdb()));
                document.add(imdb);
                document.add(Chunk.NEWLINE);
            }
            document.newPage();
        }
        // Create an internal link to the first page
        Anchor toUS = new Anchor("Go back to the first page.");
        toUS.setReference("#US");
        document.add(toUS);
        
        document.close();
        connection.close();
    }
}
MovieLinks2.java
/*
 * 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 part1.chapter02;

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.FilmFonts;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

public class MovieLinks2 {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/movie_links_2.pdf";
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new MovieLinks1().createPdf(MovieLinks1.RESULT);
        new MovieLinks2().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
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        // Create a local destination at the top of the page
        Paragraph p = new Paragraph();
        Chunk top = new Chunk("Country List", FilmFonts.BOLD);
        top.setLocalDestination("top");
        p.add(top);
        document.add(p);
        // create an external link
        Chunk imdb = new Chunk("Internet Movie Database", FilmFonts.ITALIC);
        imdb.setAnchor(new URL("http://www.imdb.com/"));
        p = new Paragraph("Click on a country, and you'll get a list of movies, "
            + "containing links to the ");
        p.add(imdb);
        p.add(".");
        document.add(p);
        // Create a remote goto
        p = new Paragraph("This list can be found in a ");
        Chunk page1 = new Chunk("separate document");
        page1.setRemoteGoto("movie_links_1.pdf", 1);
        p.add(page1);
        p.add(".");
        document.add(p);
        document.add(Chunk.NEWLINE);
        // Create a database connection and statement
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        Statement stm = connection.createStatement();
        ResultSet rs = stm.executeQuery(
            "SELECT DISTINCT mc.country_id, c.country, count(*) AS c "
            + "FROM film_country c, film_movie_country mc "
            + "WHERE c.id = mc.country_id "
            + "GROUP BY mc.country_id, country ORDER BY c DESC");
        // loop over the results
        while (rs.next()) {
        	// add country with remote goto
            Paragraph country = new Paragraph(rs.getString("country"));
            country.add(": ");
            Chunk link = new Chunk(String.format("%d movies", rs.getInt("c")));
            link.setRemoteGoto("movie_links_1.pdf", rs.getString("country_id"));
            country.add(link);
            document.add(country);
        }
        document.add(Chunk.NEWLINE);
        // Create local goto to top
        p = new Paragraph("Go to ");
        top = new Chunk("top");
        top.setLocalGoto("top");
        p.add(top);
        p.add(".");
        document.add(p);
        // step 5
        document.close();
        connection.close();
    }
}
MovieHistory.java
/*
 * 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 part1.chapter02;

import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Set;
import java.util.TreeSet;

import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.Movie;
import com.lowagie.filmfestival.MovieComparator;
import com.lowagie.filmfestival.PojoFactory;
import com.lowagie.filmfestival.PojoToElementFactory;
import com.itextpdf.text.Chapter;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Section;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.PdfWriter;

public class MovieHistory {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter02/movie_history.pdf";
    
    /** The different epochs. */
    public static final String[] EPOCH =
        { "Forties", "Fifties", "Sixties", "Seventies", "Eighties",
          "Nineties", "Twenty-first Century" };
    /** The fonts for the title. */
    public static final Font[] FONT = new Font[4];
    static {
        FONT[0] = new Font(FontFamily.HELVETICA, 24);
        FONT[1] = new Font(FontFamily.HELVETICA, 18);
        FONT[2] = new Font(FontFamily.HELVETICA, 14);
        FONT[3] = new Font(FontFamily.HELVETICA, 12, Font.BOLD);
    }
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        Set movies = 
            new TreeSet(new MovieComparator(MovieComparator.BY_YEAR));
        movies.addAll(PojoFactory.getMovies(connection));
        int epoch = -1;
        int currentYear = 0;
        Paragraph title = null;
        Chapter chapter = null;
        Section section = null;
        Section subsection = null;
        // loop over the movies
        for (Movie movie : movies) {
            // add the chapter if we're in a new epoch
            if (epoch < (movie.getYear() - 1940) / 10) {
                epoch = (movie.getYear() - 1940) / 10;
                if (chapter != null) {
                    document.add(chapter);
                }
                title = new Paragraph(EPOCH[epoch], FONT[0]);
                chapter = new Chapter(title, epoch + 1);
            }
            // switch to a new year
            if (currentYear < movie.getYear()) {
                currentYear = movie.getYear();
                title = new Paragraph(
                    String.format("The year %d", movie.getYear()), FONT[1]);
                section = chapter.addSection(title);
                section.setBookmarkTitle(String.valueOf(movie.getYear()));
                section.setIndentation(30);
                section.setBookmarkOpen(false);
                section.setNumberStyle(Section.NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT);
                section.add(new Paragraph(
                    String.format("Movies from the year %d:", movie.getYear())));
            }
            title = new Paragraph(movie.getMovieTitle(), FONT[2]);
            subsection = section.addSection(title);
            subsection.setIndentationLeft(20);
            subsection.setNumberDepth(1);
            subsection.add(new Paragraph("Duration: " + movie.getDuration(), FONT[3]));
            subsection.add(new Paragraph("Director(s):", FONT[3]));
            subsection.add(PojoToElementFactory.getDirectorList(movie));
            subsection.add(new Paragraph("Countries:", FONT[3]));
            subsection.add(PojoToElementFactory.getCountryList(movie));
        }
        document.add(chapter);
        // step 5
        document.close();
        connection.close();
    }
}
MoviePosters1.java
/*
 * 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 part1.chapter02;

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.PojoFactory;
import com.lowagie.filmfestival.Movie;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.BaseColor;

public class MoviePosters1 {
    /** Path to the resulting PDF */
    public static final String RESULT
        = "results/part1/chapter02/movie_posters_1.pdf";
    /** Path to the resources. */
    public static final String RESOURCE = "resources/posters/%s.jpg";
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new MoviePosters1().createPdf(RESULT);
    }
    
    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        Rectangle rect = new Rectangle(0, 806, 36, 842);
        rect.setBackgroundColor(BaseColor.RED);
        document.add(rect);
        // step 4
        List movies = PojoFactory.getMovies(connection);
        for (Movie movie : movies) {
            document.add(new Paragraph(movie.getMovieTitle()));
            // Add an image
            document.add(
                Image.getInstance(String.format(RESOURCE, movie.getImdb())));
        }
        // step 5
        document.close();
        
        connection.close();
    }
}
MoviePosters2.java
/*
 * 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 part1.chapter02;

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.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

public class MoviePosters2 {
    /** Path to the resulting PDF */
    public static final String RESULT
        = "results/part1/chapter02/movie_posters_2.pdf";
    /** Path to the resources. */
    public static final String RESOURCE = "resources/posters/%s.jpg";
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new MoviePosters2().createPdf(RESULT);
    }
    
    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document,
                new FileOutputStream(filename)).setStrictImageSequence(true);
        // step 3
        document.open();
        // step 4
        List movies = PojoFactory.getMovies(connection);
        for (Movie movie : movies) {
            document.add(new Paragraph(movie.getMovieTitle()));
            // Add an image
            document.add(
                Image.getInstance(String.format(RESOURCE, movie.getImdb())));
        }
        // step 5
        document.close();
        
        connection.close();
    }
}
MoviePosters3.java
/*
 * 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 part1.chapter02;

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.FilmFonts;
import com.lowagie.filmfestival.Movie;
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.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.BaseColor;

public class MoviePosters3 {
    /** Path to the resulting PDF */
    public static final String RESULT
        = "results/part1/chapter02/movie_posters_3.pdf";
    /** Path to the resources. */
    public static final String RESOURCE = "resources/posters/%s.jpg";
    
    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new MoviePosters3().createPdf(RESULT);
    }
    
    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException 
     * @throws    SQLException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException, SQLException {
    	// Create a database connection
        DatabaseConnection connection = new HsqldbConnection("filmfestival");
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer =
            PdfWriter.getInstance(document, new FileOutputStream(filename));
        writer.setStrictImageSequence(true);
        writer.setInitialLeading(18);
        // step 3
        document.open();
        // step 4
        List movies = PojoFactory.getMovies(connection);
        for (Movie movie : movies) {
        	// Create an image
            Image img = Image.getInstance(String.format(RESOURCE, movie.getImdb()));
            img.setAlignment(Image.LEFT | Image.TEXTWRAP);
            img.setBorder(Image.BOX);
            img.setBorderWidth(10);
            img.setBorderColor(BaseColor.WHITE);
            img.scaleToFit(1000, 72);
            document.add(img);
            // Create text elements
            document.add(new Paragraph(movie.getMovieTitle(), FilmFonts.BOLD));
            document.add(PojoToElementFactory.getCountryList(movie));
            document.add(new Paragraph(String.format("Year: %d", movie.getYear())));
            document.add(new Paragraph(
                String.format("Duration: %d minutes", movie.getDuration())));
            document.add(new Paragraph("Directors:"));
            document.add(PojoToElementFactory.getDirectorList(movie));
            document.add(Chunk.NEWLINE);
        }
        // step 5
        document.close();
        // Close the database connection
        connection.close();
    }
}
RiverPhoenix.java
/*
 * 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 part1.chapter02;

import java.io.FileOutputStream;
import java.io.IOException;

import com.lowagie.filmfestival.FilmFonts;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

public class RiverPhoenix {
    /** Path to the resulting PDF */
    public static final String RESULT = "results/part1/chapter02/river_phoenix.pdf";

    /**
     * Main method.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException, DocumentException {
        new RiverPhoenix().createPdf(RESULT);
    }
    
    /**
     * Creates a PDF with information about the movies
     * @param    filename the name of the PDF file that will be created.
     * @throws    DocumentException 
     * @throws    IOException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException {
    	// step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        document.add(new Paragraph("Movies featuring River Phoenix", FilmFonts.BOLD));
        document.add(createParagraph(
            "My favorite movie featuring River Phoenix was ", "0092005"));
        document.add(createParagraph(
            "River Phoenix was nominated for an academy award for his role in ", "0096018"));
        document.add(createParagraph(
            "River Phoenix played the young Indiana Jones in ", "0097576"));
        document.add(createParagraph(
            "His best role was probably in ", "0102494"));
        // step 5
        document.close();
    }
    
    /**
     * Creates a paragraph with some text about a movie with River Phoenix,
     * and a poster of the corresponding movie.
     * @param text the text about the movie
     * @param imdb the IMDB code referring to the poster
     * @throws DocumentException
     * @throws IOException
     */
    public Paragraph createParagraph(String text, String imdb)
        throws DocumentException, IOException {
        Paragraph p = new Paragraph(text);
        Image img = Image.getInstance(
                String.format("resources/posters/%s.jpg", imdb));
        img.scaleToFit(1000, 72);
        img.setRotationDegrees(-30);
        p.add(new Chunk(img, 0, -15, true));
        return p;
    }
}
DatabaseTest.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

/**
 * We'll test our SQLite database with this example
 */
namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class DatabaseTest : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = 
              "SELECT country FROM film_country ORDER BY country";
            c.Open();            
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
                document.Add(new Paragraph( r.GetString(0) ));
              }
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
CountryChunks.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

/**
 * Writes a list of countries to a PDF file.
 */
namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class CountryChunks : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream).InitialLeading = 16;
        // step 3
        document.Open();
        // add the ID in another font
        Font font = new Font(Font.FontFamily.HELVETICA, 6, Font.BOLD, BaseColor.WHITE);
        // step 4
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = 
              "SELECT country,id FROM film_country ORDER BY country";
            c.Open();
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
                var country = r.GetString(0);
                var ID = r.GetString(1);
                document.Add(new Chunk(country));
                document.Add(new Chunk(" "));
                Chunk id = new Chunk(ID, font);
                // with a background color
                id.SetBackground(BaseColor.BLACK, 1f, 0.5f, 1f, 1.5f);
                // and a text rise
                id.SetTextRise(6);
                document.Add(id);
                document.Add(Chunk.NEWLINE);
              }
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
DirectorPhrases1.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

/**
 * Writes a list of directors to a PDF file.
 */
namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class DirectorPhrases1 : IWriter {
// ===========================================================================
    /** A font that will be used in our PDF. */
    public readonly Font BOLD_UNDERLINED =
        new Font(Font.FontFamily.TIMES_ROMAN, 12, Font.BOLD | Font.UNDERLINE);
    /** A font that will be used in our PDF. */
    public readonly Font NORMAL = new Font(Font.FontFamily.TIMES_ROMAN, 12);
// ---------------------------------------------------------------------------
    /**
     * Creates a Phrase with the name and given name of a director using different fonts.
     * @param r the DbDataReader containing director records.
     */
    protected virtual Phrase CreateDirectorPhrase(DbDataReader r) {
      Phrase director = new Phrase();
      director.Add(
        new Chunk(r["name"].ToString(), BOLD_UNDERLINED)
      );
      director.Add(new Chunk(",", BOLD_UNDERLINED));
      director.Add(new Chunk(" ", NORMAL));
      director.Add(
        new Chunk(r["given_name"].ToString(), NORMAL)
      );
      return director;
    }
// ---------------------------------------------------------------------------
    public virtual void Write(Stream stream) {
      var SQL = 
@"SELECT name, given_name 
FROM film_director 
ORDER BY name, given_name";     
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = SQL;        
            c.Open();            
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
                document.Add(CreateDirectorPhrase(r));
                document.Add(Chunk.NEWLINE);
              }
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
DirectorPhrases2.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;

/**
 * Writes a list of directors to a PDF file.
 */
namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class DirectorPhrases2 : DirectorPhrases1 {
// ===========================================================================
    /** A font that will be used in our PDF. */
    public Font BOLD;
    /** A font that will be used in our PDF. */
    public new Font NORMAL;
// ---------------------------------------------------------------------------
    public DirectorPhrases2() {
      BaseFont timesbd = null;
      BaseFont times = null;
    // create a font that will be embedded
      timesbd = BaseFont.CreateFont(
        "c:/windows/fonts/timesbd.ttf", BaseFont.WINANSI, BaseFont.EMBEDDED
      );
      // create a font that will be embedded
      times = BaseFont.CreateFont(
        "c:/windows/fonts/times.ttf", BaseFont.WINANSI, BaseFont.EMBEDDED
      );
      BOLD = new Font(timesbd, 12);
      NORMAL = new Font(times, 12);
    }
// ---------------------------------------------------------------------------
    /**
     * Creates a Phrase with the name and given name of a director using different fonts.
     * @param    rs    the ResultSet containing director records.
     */
    protected override Phrase CreateDirectorPhrase(DbDataReader r) {
      Phrase director = new Phrase();
      Chunk name = new Chunk(r["name"].ToString(), BOLD);
      name.SetUnderline(0.2f, -2f);
      director.Add(name);
      director.Add(new Chunk(",", BOLD));
      director.Add(new Chunk(" ", NORMAL));
      director.Add(
        new Chunk(r["given_name"].ToString(), NORMAL)
      );
      director.Leading = 24;
      return director;
    }
// ---------------------------------------------------------------------------
    public override void Write(Stream stream) {
      base.Write(stream);
    }
// ===========================================================================
  }
}
MovieTitles.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieTitles : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
          document.Add(new Paragraph(movie.Title));
        }
      }
    }
// ===========================================================================
  }
}
MovieParagraphs1.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

/**
 * Writes a list of countries to a PDF file.
 */
namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieParagraphs1 : IWriter {
// ===========================================================================
    public virtual void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
          Paragraph p = CreateMovieInformation(movie);
          p.Alignment = Element.ALIGN_JUSTIFIED;
          p.IndentationLeft = 18;
          p.FirstLineIndent = -18;
          document.Add(p);
        }
      }
    }
// ---------------------------------------------------------------------------    
    /**
     * Creates a Paragraph containing information about a movie.
     * @param    movie    the movie for which you want to create a Paragraph
     */
    public Paragraph CreateMovieInformation(Movie movie) {
      Paragraph p = new Paragraph();
      p.Font = FilmFonts.NORMAL;
      p.Add(new Phrase("Title: ", FilmFonts.BOLDITALIC));
      p.Add(PojoToElementFactory.GetMovieTitlePhrase(movie));
      p.Add(" ");
      if (!string.IsNullOrEmpty(movie.OriginalTitle)) {
        p.Add(new Phrase("Original title: ", FilmFonts.BOLDITALIC));
        p.Add(PojoToElementFactory.GetOriginalTitlePhrase(movie));
        p.Add(" ");
      }
      p.Add(new Phrase("Country: ", FilmFonts.BOLDITALIC));
      foreach (Country country in movie.Countries) {
        p.Add(PojoToElementFactory.GetCountryPhrase(country));
        p.Add(" ");
      }
      p.Add(new Phrase("Director: ", FilmFonts.BOLDITALIC));
      foreach (Director director in movie.Directors) {
        p.Add(PojoToElementFactory.GetDirectorPhrase(director));
        p.Add(" ");
      }
      p.Add(CreateYearAndDuration(movie));
      return p;
    }
// ---------------------------------------------------------------------------    
    /**
     * Creates a Paragraph containing information about the year
     * and the duration of a movie.
     * @param    movie    the movie for which you want to create a Paragraph
     */
    public Paragraph CreateYearAndDuration(Movie movie) {
      Paragraph info = new Paragraph();
      info.Font = FilmFonts.NORMAL;
      info.Add(new Chunk("Year: ", FilmFonts.BOLDITALIC));
      info.Add(new Chunk(movie.Year.ToString(), FilmFonts.NORMAL));
      info.Add(new Chunk(" Duration: ", FilmFonts.BOLDITALIC));
      info.Add(new Chunk(movie.Duration.ToString(), FilmFonts.NORMAL));
      info.Add(new Chunk(" minutes", FilmFonts.NORMAL));
      return info;
    }    
// ===========================================================================
  }
}
MovieParagraphs2.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

/**
 * Writes a list of countries to a PDF file.
 */
namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieParagraphs2 : MovieParagraphs1 {
// ===========================================================================
    public override void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
        // Create a paragraph with the title
          Paragraph title = new Paragraph(
            PojoToElementFactory.GetMovieTitlePhrase(movie)
          );
          title.Alignment = Element.ALIGN_LEFT;
          document.Add(title);
          // Add the original title next to it using a dirty hack
          if ( !string.IsNullOrEmpty(movie.OriginalTitle) ) {
            Paragraph dummy = new Paragraph("\u00a0", FilmFonts.NORMAL);
            dummy.Leading = -18;
            document.Add(dummy);
            Paragraph originalTitle = new Paragraph(
              PojoToElementFactory.GetOriginalTitlePhrase(movie)
            );
            originalTitle.Alignment = Element.ALIGN_RIGHT;
            document.Add(originalTitle);
          }
          // Info about the director
          float indent = 20;
          // Loop over the directors
          foreach (Director pojo in movie.Directors) {
            Paragraph director = new Paragraph(
              PojoToElementFactory.GetDirectorPhrase(pojo)
            );
            director.IndentationLeft = indent;
            document.Add(director);
            indent += 20;
          }
          // Info about the country
          indent = 20;
          // Loop over the countries
          foreach (Country pojo in movie.Countries) {
            Paragraph country = new Paragraph(
              PojoToElementFactory.GetCountryPhrase(pojo)
            );
            country.Alignment = Element.ALIGN_RIGHT;
            country.IndentationRight = indent;
            document.Add(country);
            indent += 20;
          }
          // Extra info about the movie
          Paragraph info = CreateYearAndDuration(movie);
          info.Alignment = Element.ALIGN_CENTER;
          info.SpacingAfter = 36;
          document.Add(info);
        }      
      }
    }
// ===========================================================================
  }
}
PipeSplitCharacter.cs
/*
 * 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.
 */
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

/**
 * Writes a list of countries to a PDF file.
 */
namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class PipeSplitCharacter : ISplitCharacter {
// ===========================================================================
    /**
     * @see com.itextpdf.text.SplitCharacter#isSplitCharacter(int, int, int, char[],
     *      com.itextpdf.text.pdf.PdfChunk[])
     */
    public bool IsSplitCharacter(
      int start, int current, int end, char[] cc, PdfChunk[] ck) 
    {
      char c = ck == null
        ? cc[current]
        : (char) ck[Math.Min(current, ck.Length - 1)]
            .GetUnicodeEquivalent(cc[current])
      ;
      return (c == '|' || c <= ' ' || c == '-');
    }
// ===========================================================================
  }
}
MovieChain.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieChain : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document(
        new Rectangle(240, 240), 10, 10, 10, 10
      ))
      {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        // create a long Stringbuffer with movie titles
        StringBuilder sb = new StringBuilder();
        IEnumerable movies = PojoFactory.GetMovies(1);
        foreach ( Movie movie in movies  ) {
        // replace spaces with non-breaking spaces
          sb.Append(movie.MovieTitle.Replace(' ', '\u00a0'));
          // use pipe as separator
          sb.Append('|');
        }
        // Create a first chunk
        Chunk chunk1 = new Chunk(sb.ToString());
        // wrap the chunk in a paragraph and add it to the document
        Paragraph paragraph = new Paragraph("A:\u00a0");
        paragraph.Add(chunk1);
        paragraph.Alignment = Element.ALIGN_JUSTIFIED;
        document.Add(paragraph);
        document.Add(Chunk.NEWLINE);
        // define the pipe character as split character
        chunk1.SetSplitCharacter(new PipeSplitCharacter());
        // wrap the chunk in a second paragraph and add it
        paragraph = new Paragraph("B:\u00a0");
        paragraph.Add(chunk1);
        paragraph.Alignment = Element.ALIGN_JUSTIFIED;
        document.Add(paragraph);
        document.Add(Chunk.NEWLINE);

        // create a new StringBuffer with movie titles
        sb = new StringBuilder();
        foreach ( Movie movie in movies ) {
            sb.Append(movie.MovieTitle);
            sb.Append('|');
        }
        // Create a second chunk 
        Chunk chunk2 = new Chunk(sb.ToString());
        // wrap the chunk in a paragraph and add it to the document
        paragraph = new Paragraph("C:\u00a0");
        paragraph.Add(chunk2);
        paragraph.Alignment = Element.ALIGN_JUSTIFIED;
        document.Add(paragraph);
        document.NewPage();
        // define hyphenation for the chunk
        chunk2.SetHyphenation(new HyphenationAuto("en", "US", 2, 2));
        // wrap the second chunk in a second paragraph and add it
        paragraph = new Paragraph("D:\u00a0");
        paragraph.Add(chunk2);
        paragraph.Alignment = Element.ALIGN_JUSTIFIED;
        document.Add(paragraph);
        
        // go to a new page
        document.NewPage();
        // define a new space/char ratio
        writer.SpaceCharRatio = PdfWriter.NO_SPACE_CHAR_RATIO;
        // wrap the second chunk in a third paragraph and add it
        paragraph = new Paragraph("E:\u00a0");
        paragraph.Add(chunk2);
        paragraph.Alignment = Element.ALIGN_JUSTIFIED;
        document.Add(paragraph);
      }
    }
// ===========================================================================
  }
}
MovieLists1.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieLists1 : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        var SQL = 
@"SELECT DISTINCT mc.country_id, c.country, count(*) AS c
FROM film_country c, film_movie_country mc
WHERE c.id = mc.country_id
GROUP BY mc.country_id, country ORDER BY c DESC";  
        // Create a new list
        List list = new List(List.ORDERED);
        // loop over the countries
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = SQL;        
            c.Open();            
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
              // create a list item for the country
                ListItem item = new ListItem(
                  string.Format("{0}: {1} movies",
                    r["country"].ToString(), r["c"].ToString()
                  ),
                  FilmFonts.BOLDITALIC
                );
                // create a movie list for each country
                List movielist = new List(List.ORDERED, List.ALPHABETICAL);
                movielist.Lowercase = List.LOWERCASE;
                foreach (Movie movie in 
                    PojoFactory.GetMovies(r["country_id"].ToString())
                ) {
                  ListItem movieitem = new ListItem(movie.MovieTitle);
                  List directorlist = new List(List.UNORDERED);
                  foreach (Director director in movie.Directors) {
                    directorlist.Add(String.Format("{0}, {1}",
                      director.Name, director.GivenName
                    ));
                  }
                  movieitem.Add(directorlist);
                  movielist.Add(movieitem);
                }
                item.Add(movielist);
                list.Add(item);
              }
              document.Add(list);
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
MovieLists2.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieLists2 : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        var SQL = 
@"SELECT DISTINCT mc.country_id, c.country, count(*) AS c
FROM film_country c, film_movie_country mc
WHERE c.id = mc.country_id
GROUP BY mc.country_id, country ORDER BY c DESC";
        // Create a new list
        List list = new List(List.ORDERED);
        list.Autoindent = false;
        list.SymbolIndent = 36;
        // loop over the countries
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = SQL;        
            c.Open();            
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
              // create a list item for the country
                ListItem item = new ListItem(
                  string.Format("{0}: {1} movies",
                    r["country"].ToString(), r["c"].ToString()
                  )
                );
                item.ListSymbol = new Chunk(r["country_id"].ToString());
                // Create a list for the movies produced in the current country
                List movielist = new List(List.ORDERED, List.ALPHABETICAL);
                movielist.Alignindent = false;

                foreach (Movie movie in 
                    PojoFactory.GetMovies(r["country_id"].ToString())
                ) {
                  ListItem movieitem = new ListItem(movie.MovieTitle);
                  List directorlist = new List(List.ORDERED);
                  directorlist.PreSymbol = "Director ";
                  directorlist.PostSymbol = ": ";
                  foreach (Director director in movie.Directors) {
                    directorlist.Add(String.Format("{0}, {1}",
                      director.Name, director.GivenName
                    ));
                  }


                  movieitem.Add(directorlist);
                  movielist.Add(movieitem);
                }
                item.Add(movielist);
                list.Add(item);
              }
              document.Add(list);
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
MovieLists3.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieLists3 : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        var SQL = 
@"SELECT DISTINCT mc.country_id, c.country, count(*) AS c
FROM film_country c, film_movie_country mc
WHERE c.id = mc.country_id
GROUP BY mc.country_id, country ORDER BY c DESC";  
        // Create a list for the countries
        List list = new RomanList();
        // loop over the countries
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = SQL;        
            c.Open();            
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
              // create a list item for the country
                ListItem item = new ListItem(
                  string.Format("{0}: {1} movies",
                    r["country"].ToString(), r["c"].ToString()
                  )
                );
                // Create a list for the movies
                List movielist = new GreekList();
                movielist.Lowercase = List.LOWERCASE;
                // Loop over the movies
                foreach (Movie movie in 
                    PojoFactory.GetMovies(r["country_id"].ToString())
                ) {
                  ListItem movieitem = new ListItem(movie.MovieTitle);
                  // Create a list for the directors
                  List directorlist = new ZapfDingbatsNumberList(0); 
                  // Loop over the directors                 
                  foreach (Director director in movie.Directors) {
                    directorlist.Add(String.Format("{0}, {1}",
                      director.Name, director.GivenName
                    ));
                  }
                  movieitem.Add(directorlist);
                  movielist.Add(movieitem);
                }
                item.Add(movielist);
                list.Add(item);
              }
              document.Add(list);
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
MovieLists4.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieLists4 : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        var SQL = 
  @"SELECT DISTINCT mc.country_id, c.country, count(*) AS c
  FROM film_country c, film_movie_country mc
  WHERE c.id = mc.country_id
  GROUP BY mc.country_id, country ORDER BY c DESC";  
        // Create a list for the countries
        List list = new List(List.ORDERED);
        list.First = 9;
        // loop over the countries
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = SQL;        
            c.Open();            
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
              // create a list item for the country
                ListItem item = new ListItem(
                  string.Format("{0}: {1} movies",
                    r["country"].ToString(), r["c"].ToString()
                  )
                );
                // Create a list for the movies
                List movielist = new List();
                movielist.ListSymbol= new Chunk("Movie: ", FilmFonts.BOLD);
                foreach (Movie movie in 
                    PojoFactory.GetMovies(r["country_id"].ToString())
                ) {
                  ListItem movieitem = new ListItem(movie.MovieTitle);
                  // Create a list for the directors
                  List directorlist = new ZapfDingbatsList(42);
                  foreach (Director director in movie.Directors) {
                    directorlist.Add(String.Format("{0}, {1}",
                      director.Name, director.GivenName
                    ));
                  }
                  movieitem.Add(directorlist);
                  movielist.Add(movieitem);
                }
                item.Add(movielist);
                list.Add(item);
              }
              document.Add(list);
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
PositionedArrow.cs
/*
 * 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.
 */
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.draw;

/**
 * Subclass of VerticalPositionMark that draws an arrow in the left
 * or right margin.
 */
namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class PositionedArrow : VerticalPositionMark {
// ===========================================================================
    /** Indicates if the arrow needs to be drawn to the left. */
    protected bool left;
    
    /** Thee font that will be used to draw the arrow. */
    protected BaseFont zapfdingbats;

    /** An arrow pointing to the right will be added on the left. */
    public static PositionedArrow LEFT {
      get { return new PositionedArrow(true); }
    }
    /** An arrow pointing to the left will be added on the right. */
    public static PositionedArrow RIGHT {
      get { return new PositionedArrow(false); }
    }
// ---------------------------------------------------------------------------    
    /**
     * Constructs a positioned Arrow mark.
     * @param    left    if true, an arrow will be drawn on the left;
     * otherwise, it will be drawn on the right.
     * @throws IOException 
     * @throws DocumentException 
     */
    public PositionedArrow(bool left) {
      this.left = left;
      try {
        zapfdingbats = BaseFont.CreateFont(
          BaseFont.ZAPFDINGBATS, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED
        );
      }
      catch {
        zapfdingbats = null;
        throw;
      }
    }
// ---------------------------------------------------------------------------    
    /**
     * Draws a character representing an arrow at the current position.
     * @see com.itextpdf.text.pdf.draw.VerticalPositionMark#draw(
     *      com.itextpdf.text.pdf.PdfContentByte, float, float, float, float, float)
     */
    // i'm so stupid; originally forgot to override parent method and wondered
    // why the arrows weren't being drawn...
    public override void Draw(
      PdfContentByte canvas, float llx, float lly, float urx, float ury, float y
    ) {
      canvas.BeginText();
      canvas.SetFontAndSize(zapfdingbats, 12);
      if (left) {
        canvas.ShowTextAligned(Element.ALIGN_CENTER,
          ((char) 220).ToString(), llx - 10, y, 0
        );
      }
      else {
        canvas.ShowTextAligned(Element.ALIGN_CENTER,
          ((char) 220).ToString(), urx + 10, y + 8, 180
        );
      }
      canvas.EndText();
    }
// ===========================================================================
  }
}
StarSeparator.cs
/*
 * 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.
 */
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.draw;

/**
 * does **NOT** write PDF file; class used for drawing only.
 */
namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class StarSeparator : IDrawInterface {
// ===========================================================================
    /** The font that will be used to draw the arrow. */
    protected BaseFont bf;
// --------------------------------------------------------------------------- 
    public static StarSeparator LINE {
      get { return new StarSeparator(); }
    }
// ---------------------------------------------------------------------------    
    /**
     * Constructs a positioned Arrow mark.
     * @param    left    if true, an arrow will be drawn on the left;
     * otherwise, it will be drawn on the right.
     * @throws IOException 
     * @throws DocumentException 
     */
    public StarSeparator() {
      try {
        bf = BaseFont.CreateFont();
      } catch {
        bf = null;
        throw;
      }
    }
// ---------------------------------------------------------------------------    
    /**
     * Draws three stars to separate two paragraphs.
     * @see com.itextpdf.text.pdf.draw.DrawInterface#draw(
     * com.itextpdf.text.pdf.PdfContentByte, float, float, float, float, float)
     */
    public void Draw(
      PdfContentByte canvas, float llx, float lly, float urx, float ury, float y
    ) {
      float middle = (llx + urx) / 2;
      canvas.BeginText();
      canvas.SetFontAndSize(bf, 10);
      canvas.ShowTextAligned(Element.ALIGN_CENTER, "*", middle, y, 0);
      canvas.ShowTextAligned(Element.ALIGN_CENTER, "*  *", middle, y -10, 0);
      canvas.EndText();
    }
// ===========================================================================
  }
}
DirectorOverview1.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.util.collections;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.draw;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class DirectorOverview1 : IWriter {
// ===========================================================================
    public const string SQL = 
@"SELECT DISTINCT d.id, d.name, d.given_name, count(*) AS c 
  FROM film_director d, film_movie_director md 
  WHERE d.id = md.director_id 
  GROUP BY d.id, d.name, d.given_name ORDER BY name";
// ---------------------------------------------------------------------------
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        Director director;
        // creating separators
        LineSeparator line
            = new LineSeparator(1, 100, null, Element.ALIGN_CENTER, -2);
        Paragraph stars = new Paragraph(20);
        stars.Add(new Chunk(StarSeparator.LINE));
        stars.SpacingAfter = 30;
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = SQL;
            c.Open();
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
                // get the director object and use it in a Paragraph
                director = PojoFactory.GetDirector(r);
                Paragraph p = new Paragraph(
                    PojoToElementFactory.GetDirectorPhrase(director));
                // if there are more than 2 movies for this director
                // an arrow is added to the left
                var count = Convert.ToInt32(r["c"]);
                if (count > 2) {
                  p.Add(PositionedArrow.LEFT);
                }
                p.Add(line);
                // add the paragraph with the arrow to the document
                document.Add(p);
                // Get the movies of the director
                var director_id = Convert.ToInt32(r["id"]);
                // LINQ allows us to sort on any movie object property inline;
                // let's sort by Movie.Year, Movie.Title
                var by_year = from m in PojoFactory.GetMovies(director_id)
                    orderby m.Year, m.Title
                    select m;
                foreach (Movie movie in by_year) {
                  p = new Paragraph(movie.MovieTitle);
                  p.Add(": ");
                  p.Add(new Chunk(movie.Year.ToString()));
                  if (movie.Year > 1999) p.Add(PositionedArrow.RIGHT);
                  document.Add(p);
                }                
                // add a star separator after the director info is added
                document.Add(stars);           
              }
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
DirectorOverview2.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using System.Linq;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.draw;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class DirectorOverview2 : IWriter {
// ===========================================================================
    public const string SQL = 
@"SELECT DISTINCT d.id, d.name, d.given_name, count(*) AS c 
FROM film_director d, film_movie_director md 
  WHERE d.id = md.director_id
GROUP BY d.id, d.name, d.given_name ORDER BY c DESC";
// ---------------------------------------------------------------------------
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        Director director;
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = SQL;
            c.Open();
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
                // create a paragraph for the director
                director = PojoFactory.GetDirector(r);
                Paragraph p = new Paragraph(
                    PojoToElementFactory.GetDirectorPhrase(director));
                // add a dotted line separator
                p.Add(new Chunk(new DottedLineSeparator()));
                // adds the number of movies of this director
                p.Add(string.Format("movies: {0}", Convert.ToInt32(r["c"])));
                document.Add(p);
                // Creates a list
                List list = new List(List.ORDERED);
                list.IndentationLeft = 36;
                list.IndentationRight = 36;
                // Gets the movies of the current director
                var director_id = Convert.ToInt32(r["id"]);
                ListItem movieitem;
                // LINQ allows us to on sort any movie object property inline;
                // let's sort by Movie.Year, Movie.Title
                var by_year = from m in PojoFactory.GetMovies(director_id)
                    orderby m.Year, m.Title
                    select m;
                // loops over the movies
                foreach (Movie movie in by_year) {
                // creates a list item with a movie title
                  movieitem = new ListItem(movie.MovieTitle);
                  // adds a vertical position mark as a separator
                  movieitem.Add(new Chunk(new VerticalPositionMark()));
                  var yr = movie.Year;
                  // adds the year the movie was produced
                  movieitem.Add(new Chunk( yr.ToString() ));
                  // add an arrow to the right if the movie dates from 2000 or later
                  if (yr > 1999) {
                    movieitem.Add(PositionedArrow.RIGHT);
                  }
                  // add the list item to the list
                  list.Add(movieitem);
                }
                // add the list to the document
                document.Add(list);           
              }
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
DirectorOverview3.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using System.Linq; 
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.draw;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class DirectorOverview3 : IWriter {
// ===========================================================================
    public const string SQL = 
@"SELECT DISTINCT d.id, d.name, d.given_name, count(*) AS c
FROM film_director d, film_movie_director md
  WHERE d.id = md.director_id
GROUP BY d.id, d.name, d.given_name ORDER BY c DESC";
// ---------------------------------------------------------------------------
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        Director director;
        // creates line separators
        Chunk CONNECT = new Chunk(
          new LineSeparator(0.5f, 95, BaseColor.BLUE, Element.ALIGN_CENTER, 3.5f)
        );
        LineSeparator UNDERLINE = new LineSeparator(
          1, 100, null, Element.ALIGN_CENTER, -2
        );
        // creates tabs
        Chunk tab1 = new Chunk(new VerticalPositionMark(), 200, true);
        Chunk tab2 = new Chunk(new VerticalPositionMark(), 350, true);
        Chunk tab3 = new Chunk(new DottedLineSeparator(), 450, true);
        
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = SQL;
            c.Open();
            using (var r = cmd.ExecuteReader()) {
              // loops over the directors
              while (r.Read()) {
                // creates a paragraph with the director name
                director = PojoFactory.GetDirector(r);
                Paragraph p = new Paragraph(
                    PojoToElementFactory.GetDirectorPhrase(director));
                // adds a separator
                p.Add(CONNECT);
                // adds more info about the director
                p.Add(string.Format("movies: {0}", Convert.ToInt32(r["c"])));
                // adds a separator
                p.Add(UNDERLINE);
                // adds the paragraph to the document
                document.Add(p);
                // gets all the movies of the current director
                var director_id = Convert.ToInt32(r["id"]);
                // LINQ allows us to sort on any movie object property inline;
                // let's sort by Movie.Year, Movie.Title
                var by_year = from m in PojoFactory.GetMovies(director_id)
                    orderby m.Year, m.Title
                    select m;
                // loops over the movies
                foreach (Movie movie in by_year) {
                // create a Paragraph with the movie title
                  p = new Paragraph(movie.MovieTitle);
                  // insert a tab
                  p.Add(new Chunk(tab1));
                  // add the original title
                  var mt = movie.OriginalTitle;
                  if (mt != null) p.Add(new Chunk(mt));
                  // insert a tab
                  p.Add(new Chunk(tab2));
                  // add the run length of the movie
                  p.Add(new Chunk(string.Format("{0} minutes", movie.Duration)));
                  // insert a tab
                  p.Add(new Chunk(tab3));
                  // add the production year of the movie
                  p.Add(new Chunk(
                    string.Format("{0}", movie.Year.ToString())
                  ));
                  // add the paragraph to the document
                  document.Add(p);
                }
                document.Add(Chunk.NEWLINE);           
              }
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
MovieLinks1.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieLinks1 : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      var SQL = 
@"SELECT DISTINCT mc.country_id, c.country, count(*) AS c 
FROM film_country c, film_movie_country mc 
  WHERE c.id = mc.country_id
GROUP BY mc.country_id, country ORDER BY c DESC";          
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = SQL;
            c.Open();            
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
                Paragraph country = new Paragraph();
                // the name of the country will be a destination
                Anchor dest = new Anchor(
                  r["country"].ToString(), FilmFonts.BOLD
                );
                dest.Name = r["country_id"].ToString();
                country.Add(dest);
                country.Add(string.Format(": {0} movies", r["c"].ToString()));
                document.Add(country);
                // loop over the movies
                foreach (Movie movie in 
                    PojoFactory.GetMovies(r["country_id"].ToString()))
                {
                // the movie title will be an external link
                  Anchor imdb = new Anchor(movie.MovieTitle);
                  imdb.Reference = string.Format(
                    "http://www.imdb.com/title/tt{0}/", movie.Imdb
                  );
                  document.Add(imdb);
                  document.Add(Chunk.NEWLINE);
                }
                document.NewPage();
              }
              // Create an internal link to the first page
              Anchor toUS = new Anchor("Go back to the first page.");
              toUS.Reference = "#US";
              document.Add(toUS);           
            }
          }
        }
      }
    }
// ===========================================================================
  }
}
MovieLinks2.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

/**
 * We'll test our SQLite database with this example
 */
namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieLinks2 : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        // Create a local destination at the top of the page
        Paragraph p = new Paragraph();
        Chunk top = new Chunk("Country List", FilmFonts.BOLD);
        top.SetLocalDestination("top");
        p.Add(top);
        document.Add(p);
        // create an external link
        Chunk imdb = new Chunk("Internet Movie Database", FilmFonts.ITALIC);
        imdb.SetAnchor(new Uri("http://www.imdb.com/"));
        p = new Paragraph(
          "Click on a country, and you'll get a list of movies, containing links to the "
        );
        p.Add(imdb);
        p.Add(".");
        document.Add(p);
        // Create a remote goto
        p = new Paragraph("This list can be found in a ");
        Chunk page1 = new Chunk("separate document");
        page1.SetRemoteGoto("movie_links_1.pdf", 1);
        p.Add(page1);
        p.Add(".");
        document.Add(p);
        document.Add(Chunk.NEWLINE);
        
        var SQL =
@"SELECT DISTINCT mc.country_id, c.country, count(*) AS c 
FROM film_country c, film_movie_country mc
WHERE c.id = mc.country_id 
GROUP BY mc.country_id, country ORDER BY c DESC";        
        // Create a database connection and statement
        using (var c =  AdoDB.Provider.CreateConnection()) {
          c.ConnectionString = AdoDB.CS;
          using (DbCommand cmd = c.CreateCommand()) {
            cmd.CommandText = SQL;        
            c.Open();            
            using (var r = cmd.ExecuteReader()) {
              while (r.Read()) {
              // add country with remote goto
                Paragraph country = new Paragraph(r["country"].ToString());
                country.Add(": ");
                Chunk link = new Chunk(string.Format(
                  "{0} movies", Convert.ToInt32(r["c"])
                ));
                link.SetRemoteGoto(
                  "movie_links_1.pdf", r["country_id"].ToString()
                );
                country.Add(link);
                document.Add(country);
              }
            }
          }
        }      
        document.Add(Chunk.NEWLINE);
        // Create local goto to top
        p = new Paragraph("Go to ");
        top = new Chunk("top");
        top.SetLocalGoto("top");
        p.Add(top);
        p.Add(".");
        document.Add(p);        
      }
    }
// ===========================================================================
  }
}
MovieHistory.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MovieHistory : IWriter {
// ===========================================================================
    /** The different epochs. */
    public static readonly string[] EPOCH = { 
      "Forties", "Fifties", "Sixties", "Seventies", "Eighties",
      "Nineties", "Twenty-first Century" 
    };
    /** The fonts for the title. */
    public static Font[] FONT = new Font[4];
    static MovieHistory() {
      FONT[0] = new Font(Font.FontFamily.HELVETICA, 24);
      FONT[1] = new Font(Font.FontFamily.HELVETICA, 18);
      FONT[2] = new Font(Font.FontFamily.HELVETICA, 14);
      FONT[3] = new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD);
    }
// ---------------------------------------------------------------------------
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        int epoch = -1;
        int currentYear = 0;
        Paragraph title = null;
        Chapter chapter = null;
        Section section = null;
        Section subsection = null;        
        IEnumerable movies = PojoFactory.GetMovies(true);
        // loop over the movies
        foreach (Movie movie in movies) {
          int yr = movie.Year;
        // add the chapter if we're in a new epoch
          if (epoch < (yr - 1940) / 10) {
            epoch = (yr - 1940) / 10;
            if (chapter != null) {
              document.Add(chapter);
            }
            title = new Paragraph(EPOCH[epoch], FONT[0]);
            chapter = new Chapter(title, epoch + 1);
          }
          // switch to a new year
          if (currentYear < yr) {
              currentYear = yr;
              title = new Paragraph(
                string.Format("The year {0}", yr), FONT[1]
              );
              section = chapter.AddSection(title);
              section.BookmarkTitle = yr.ToString();
              section.Indentation = 30;
              section.BookmarkOpen = false;
              section.NumberStyle = Section.NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT;
              section.Add(new Paragraph(
                string.Format("Movies from the year {0}:", yr)
              ));
          }
          title = new Paragraph(movie.Title, FONT[2]);
          subsection = section.AddSection(title);
          subsection.IndentationLeft = 20;
          subsection.NumberDepth = 1;
          subsection.Add(new Paragraph("Duration: " + movie.Duration.ToString(), FONT[3]));
          subsection.Add(new Paragraph("Director(s):", FONT[3]));
          subsection.Add(PojoToElementFactory.GetDirectorList(movie));
          subsection.Add(new Paragraph("Countries:", FONT[3]));
          subsection.Add(PojoToElementFactory.GetCountryList(movie));
        }
        document.Add(chapter);
      }
    }
// ===========================================================================
  }
}
MoviePosters1.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MoviePosters1 : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      string RESOURCE = Utility.ResourcePosters;
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        Rectangle rect = new Rectangle(0, 806, 36, 842);
        rect.BackgroundColor = BaseColor.RED;
        document.Add(rect);
        // step 4
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
          document.Add(new Paragraph(movie.MovieTitle));
          // Add an image
          document.Add(
            Image.GetInstance(Path.Combine(RESOURCE, movie.Imdb + ".jpg"))
          );
        }
      }
    }
// ===========================================================================
  }
}
MoviePosters2.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MoviePosters2 : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      string RESOURCE = Utility.ResourcePosters;
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream)
          .StrictImageSequence = true;
        ;
        // step 3
        document.Open();
        Rectangle rect = new Rectangle(0, 806, 36, 842);
        rect.BackgroundColor = BaseColor.RED;
        document.Add(rect);
        // step 4
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
          document.Add(new Paragraph(movie.MovieTitle));
          // Add an image
          document.Add(
            Image.GetInstance(Path.Combine(RESOURCE, movie.Imdb + ".jpg"))
          );
        }
      }
    }
// ===========================================================================
  }
}
MoviePosters3.cs
/*
 * 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.
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class MoviePosters3 : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      string RESOURCE = Utility.ResourcePosters;
      // step 1
      using (Document document = new Document()) {
        // step 2
        var writer = PdfWriter.GetInstance(document, stream);
        writer.StrictImageSequence = true;
        writer.InitialLeading = 18;
        // step 3
        document.Open();
        Rectangle rect = new Rectangle(0, 806, 36, 842);
        rect.BackgroundColor = BaseColor.RED;
        document.Add(rect);
        // step 4
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
        // Create an image
          Image img = Image.GetInstance(
            Path.Combine(RESOURCE, movie.Imdb + ".jpg")
          );
          img.Alignment = Image.ALIGN_LEFT | Image.TEXTWRAP;
          img.Border = Image.BOX;
          img.BorderWidth = 10;
          img.BorderColor = BaseColor.WHITE;
          img.ScaleToFit(1000, 72);
          document.Add(img);
          // Create text elements
          document.Add(new Paragraph(movie.MovieTitle, FilmFonts.BOLD));
          document.Add(PojoToElementFactory.GetCountryList(movie));
          document.Add(new Paragraph(
            String.Format("Year: {0}", movie.Year)
          ));
          document.Add(new Paragraph(
              String.Format("Duration: {0} minutes", movie.Duration))
          );
          document.Add(new Paragraph("Directors:"));
          document.Add(PojoToElementFactory.GetDirectorList(movie));
          document.Add(Chunk.NEWLINE);
        }
      }
    }
// ===========================================================================
  }
}
RiverPhoenix.cs
/*
 * 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.
 */
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter02 {
  public class RiverPhoenix : IWriter {
// ===========================================================================
    public readonly string RESOURCE = Utility.ResourcePosters;
// ---------------------------------------------------------------------------
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        document.Add(new Paragraph(
          "Movies featuring River Phoenix", FilmFonts.BOLD
        ));
        document.Add(CreateParagraph(
          "My favorite movie featuring River Phoenix was ", "0092005"
        ));
        document.Add(CreateParagraph(
          "River Phoenix was nominated for an academy award for his role in ", "0096018"
        ));
        document.Add(CreateParagraph(
          "River Phoenix played the young Indiana Jones in ", "0097576"
        ));
        document.Add(CreateParagraph(
          "His best role was probably in ", "0102494"
        ));
      }
    }
// ---------------------------------------------------------------------------
    /**
     * Creates a paragraph with some text about a movie with River Phoenix,
     * and a poster of the corresponding movie.
     * @param text the text about the movie
     * @param imdb the IMDB code referring to the poster
     */
    public Paragraph CreateParagraph(String text, String imdb) {
      Paragraph p = new Paragraph(text);
      Image img = Image.GetInstance(Path.Combine(RESOURCE, imdb + ".jpg"));
      img.ScaleToFit(1000, 72);
      img.RotationDegrees = -30;
      p.Add(new Chunk(img, 0, -15, true));
      return p;
    }
// ===========================================================================
  }
}
Contact

Still have questions? 

We're happy to answer your questions. Reach out to us and we'll get back to you shortly.

Contact us
Stay updated

Join 11,000+ subscribers and become an iText PDF expert by staying up to date with our new products, updates, tips, technical solutions and happenings.

Subscribe Now