Chapter 3: Adding content at absolute positions

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

10th October 2015
admin-marketing

Switch code for this example

FestivalOpening.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.chapter03;

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

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;

public class FestivalOpening {

    /** The resulting PDF. */
    public static final String RESULT
        = "results/part1/chapter03/festival_opening.pdf";
    /** The movie poster. */
    public static final String RESOURCE = "resources/img/loa.jpg";

    /**
     * Main method.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// step 1
        Document document = new Document(PageSize.POSTCARD, 30, 30, 30, 30);
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        // Create and add a Paragraph
        Paragraph p
            = new Paragraph("Foobar Film Festival", new Font(FontFamily.HELVETICA, 22));
        p.setAlignment(Element.ALIGN_CENTER);
        document.add(p);
        // Create and add an Image
        Image img = Image.getInstance(RESOURCE);
        img.setAbsolutePosition(
            (PageSize.POSTCARD.getWidth() - img.getScaledWidth()) / 2,
            (PageSize.POSTCARD.getHeight() - img.getScaledHeight()) / 2);
        document.add(img);
        // Now we go to the next page
        document.newPage();
        document.add(p);
        document.add(img);
        // Add text on top of the image
        PdfContentByte over = writer.getDirectContent();
        over.saveState();
        float sinus = (float)Math.sin(Math.PI / 60);
        float cosinus = (float)Math.cos(Math.PI / 60);
        BaseFont bf = BaseFont.createFont();
        over.beginText();
        over.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
        over.setLineWidth(1.5f);
        over.setRGBColorStroke(0xFF, 0x00, 0x00);
        over.setRGBColorFill(0xFF, 0xFF, 0xFF);
        over.setFontAndSize(bf, 36);
        over.setTextMatrix(cosinus, sinus, -sinus, cosinus, 50, 324);
        over.showText("SOLD OUT");
        over.endText();
        over.restoreState();
        // Add a rectangle under the image
        PdfContentByte under = writer.getDirectContentUnder();
        under.saveState();
        under.setRGBColorFill(0xFF, 0xD7, 0x00);
        under.rectangle(5, 5,
            PageSize.POSTCARD.getWidth() - 10, PageSize.POSTCARD.getHeight() - 10);
        under.fill();
        under.restoreState();
        // step 5
        document.close();
    }
}
GraphicsStateStack.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.chapter03;

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

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;

public class GraphicsStateStack {
    
    /** The resulting PDF. */
    public static final String RESULT
        = "results/part1/chapter03/graphics_state.pdf";

    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// step 1
        Document document = new Document(new Rectangle(200, 120));
        // step 2
        PdfWriter writer
             = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        PdfContentByte canvas = writer.getDirectContent();
        // state 1:
        canvas.setRGBColorFill(0xFF, 0x45, 0x00);
        // fill a rectangle in state 1
        canvas.rectangle(10, 10, 60, 60);
        canvas.fill();
        canvas.saveState();
        // state 2;
        canvas.setLineWidth(3);
        canvas.setRGBColorFill(0x8B, 0x00, 0x00);
        // fill and stroke a rectangle in state 2
        canvas.rectangle(40, 20, 60, 60);
        canvas.fillStroke();
        canvas.saveState();
        // state 3:
        canvas.concatCTM(1, 0, 0.1f, 1, 0, 0);
        canvas.setRGBColorStroke(0xFF, 0x45, 0x00);
        canvas.setRGBColorFill(0xFF, 0xD7, 0x00);
        // fill and stroke a rectangle in state 3
        canvas.rectangle(70, 30, 60, 60);
        canvas.fillStroke();
        canvas.restoreState();
        // stroke a rectangle in state 2
        canvas.rectangle(100, 40, 60, 60);
        canvas.stroke();
        canvas.restoreState();
        // fill and stroke a rectangle in state 1
        canvas.rectangle(130, 50, 60, 60);
        canvas.fillStroke();
        // step 5
        document.close();
    }
}
MovieTimeTable.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.chapter03;

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

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.BaseColor;

/**
 * Draws a time table to the direct content using lines and simple shapes.
 */
public class MovieTimeTable {

    /** The resulting PDF. */
    public static final String RESULT = "results/part1/chapter03/time_table.pdf";
    
    /**
     * Creates a PDF file containing a time table for our filmfestival.
     * @param    filename    the name of the PDF file
     * @throws DocumentException
     * @throws IOException 
     */
    public void createPdf(String filename)
        throws DocumentException, IOException {
    	// step 1
        Document document = new Document(PageSize.A4.rotate());
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        drawTimeTable(writer.getDirectContentUnder());
        drawTimeSlots(writer.getDirectContent());
        // step 5
        document.close();
    }

    /** The number of locations on our time table. */
    public static final int LOCATIONS = 9;
    /** The number of time slots on our time table. */
    public static final int TIMESLOTS = 32;
    
    /** The offset to the left of our time table. */
    public static final float OFFSET_LEFT = 76;
    /** The width of our time table. */
    public static final float WIDTH = 740;
    /** The offset from the bottom of our time table. */
    public static final float OFFSET_BOTTOM = 36;
    /** The height of our time table */
    public static final float HEIGHT = 504;
    
    /** The offset of the location bar next to our time table. */
    public static final float OFFSET_LOCATION = 26;
    /** The width of the location bar next to our time table. */
    public static final float WIDTH_LOCATION = 48;
    
    /** The height of a bar showing the movies at one specific location. */
    public static final float HEIGHT_LOCATION = HEIGHT / LOCATIONS;
    /** The width of a time slot. */
    public static final float WIDTH_TIMESLOT = WIDTH / TIMESLOTS;
    
    /**
     * Draws the time table for a day at the film festival.
     * @param directcontent a canvas to which the time table has to be drawn.
     */
    protected void drawTimeTable(PdfContentByte directcontent) {        
        directcontent.saveState();
        
        directcontent.setLineWidth(1.2f);
        float llx, lly, urx, ury;
        
        llx = OFFSET_LEFT;
        lly = OFFSET_BOTTOM;
        urx = OFFSET_LEFT + WIDTH;
        ury = OFFSET_BOTTOM + HEIGHT;
        directcontent.moveTo(llx, lly);
        directcontent.lineTo(urx, lly);
        directcontent.lineTo(urx, ury);
        directcontent.lineTo(llx, ury);
        directcontent.closePath();
        directcontent.stroke();
        
        llx = OFFSET_LOCATION;
        lly = OFFSET_BOTTOM;
        urx = OFFSET_LOCATION + WIDTH_LOCATION;
        ury = OFFSET_BOTTOM + HEIGHT;
        directcontent.moveTo(llx, lly);
        directcontent.lineTo(urx, lly);
        directcontent.lineTo(urx, ury);
        directcontent.lineTo(llx, ury);
        directcontent.closePathStroke();
        
        directcontent.setLineWidth(1);
        directcontent.moveTo(OFFSET_LOCATION + WIDTH_LOCATION / 2, OFFSET_BOTTOM);
        directcontent.lineTo(OFFSET_LOCATION + WIDTH_LOCATION / 2, OFFSET_BOTTOM + HEIGHT);
        float y;
        for (int i = 1; i < LOCATIONS; i++) {
            y = OFFSET_BOTTOM + (i * HEIGHT_LOCATION);
            if (i == 2 || i == 6) {
                directcontent.moveTo(OFFSET_LOCATION, y);
                directcontent.lineTo(OFFSET_LOCATION + WIDTH_LOCATION, y);
            }
            else {
                directcontent.moveTo(OFFSET_LOCATION + WIDTH_LOCATION / 2, y);
                directcontent.lineTo(OFFSET_LOCATION + WIDTH_LOCATION, y);
            }
            directcontent.moveTo(OFFSET_LEFT, y);
            directcontent.lineTo(OFFSET_LEFT + WIDTH, y);
        }
        directcontent.stroke();
        
        directcontent.restoreState();
    }
    
    /**
     * Draws the time slots for a day at the film festival.
     * @param directcontent the canvas to which the time table has to be drawn.
     */
    protected void drawTimeSlots(PdfContentByte directcontent) {
        directcontent.saveState();
        float x;
        for (int i = 1; i < TIMESLOTS; i++) {
            x = OFFSET_LEFT + (i * WIDTH_TIMESLOT);
            directcontent.moveTo(x, OFFSET_BOTTOM);
            directcontent.lineTo(x, OFFSET_BOTTOM + HEIGHT);
        }
        directcontent.setLineWidth(0.3f);
        directcontent.setColorStroke(BaseColor.GRAY);
        directcontent.setLineDash(3, 1);
        directcontent.stroke();
        directcontent.restoreState();
    }
    
    /**
     * Main method creating the PDF.
     * @param    args    no arguments needed
     * @throws IOException 
     * @throws DocumentException 
     */
    public static void main(String[] args)
        throws DocumentException, IOException {
        new MovieTimeTable().createPdf(RESULT);
    }
}
MovieTimeBlocks.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.chapter03;

import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.Date;
import java.sql.Time;
import java.util.List;

import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.PojoFactory;
import com.lowagie.filmfestival.Screening;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.html.WebColors;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.BaseColor;

/**
 * Draws a time table to the direct content using lines and simple shapes,
 * adding blocks representing a movies.
 */
public class MovieTimeBlocks extends MovieTimeTable {

    /** The resulting PDF. */
    public static final String RESULT
        = "results/part1/chapter03/time_blocks.pdf";

    /**
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws    DocumentException 
     * @throws    IOException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException {
    	// step 1
        Document document = new Document(PageSize.A4.rotate());
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        PdfContentByte over = writer.getDirectContent();
        PdfContentByte under = writer.getDirectContentUnder();
        try {
            DatabaseConnection connection = new HsqldbConnection("filmfestival");
            locations = PojoFactory.getLocations(connection);
            List days = PojoFactory.getDays(connection);
            List screenings;
            for (Date day : days) {
                drawTimeTable(under);
                drawTimeSlots(over);
                screenings = PojoFactory.getScreenings(connection, day);
                for (Screening screening : screenings) {
                    drawBlock(screening, under, over);
                }
                document.newPage();
            }
            connection.close();
        }
        catch(SQLException sqle) {
            sqle.printStackTrace();
            document.add(new Paragraph("Database error: " + sqle.getMessage()));
        }
        // step 5
        document.close();
    }
    
    /**
     * Draws a colored block on the time table, corresponding with
     * the screening of a specific movie.
     * @param    screening    a screening POJO, contains a movie and a category
     * @param    under    the canvas to which the block is drawn
     */
    protected void drawBlock(Screening screening, PdfContentByte under, PdfContentByte over) {
        under.saveState();
        BaseColor color = WebColors.getRGBColor(
            "#" + screening.getMovie().getEntry().getCategory().getColor());
        under.setColorFill(color);
        Rectangle rect = getPosition(screening);
        under.rectangle(
                rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight());
        under.fill();
        over.rectangle(
            rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight());
        over.stroke();
        under.restoreState();
    }
    
    /** The "offset time" for our calendar sheets. */
    public static final long TIME930 = Time.valueOf("09:30:00").getTime();
    
    /** The width of one minute. */
    public static final float MINUTE = WIDTH_TIMESLOT / 30f;
    
    /** A list containing all the locations. */
    protected List locations;
    
    /**
     * Calculates the position of a rectangle corresponding with a screening.
     * @param    screening    a screening POJO, contains a movie
     * @return    a Rectangle
     */
    protected Rectangle getPosition(Screening screening) {
        float llx, lly, urx, ury;
        long minutesAfter930 = (screening.getTime().getTime() - TIME930) / 60000l;
        llx = OFFSET_LEFT + (MINUTE * minutesAfter930);
        int location = locations.indexOf(screening.getLocation()) + 1;
        lly = OFFSET_BOTTOM + (LOCATIONS - location) * HEIGHT_LOCATION;
        urx = llx + MINUTE * screening.getMovie().getDuration();
        ury = lly + HEIGHT_LOCATION;
        Rectangle rect = new Rectangle(llx, lly, urx, ury);
        return rect;
    }
    
    /**
     * Main method creating the PDF.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException, DocumentException {
        new MovieTimeBlocks().createPdf(RESULT);
    }
}
FoobarFilmFestival.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.chapter03;

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

import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.BaseColor;

public class FoobarFilmFestival {

    public static final String RESULT
        = "results/part1/chapter03/foobar_film_festival.pdf";

    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// step 1
        Document document = new Document();
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        Chunk c;
        String foobar = "Foobar Film Festival";
        // Measuring a String in Helvetica
        Font helvetica = new Font(FontFamily.HELVETICA, 12);
        BaseFont bf_helv = helvetica.getCalculatedBaseFont(false);
        float width_helv = bf_helv.getWidthPoint(foobar, 12);
        c = new Chunk(foobar + ": " + width_helv, helvetica);
        document.add(new Paragraph(c));
        document.add(new Paragraph(String.format("Chunk width: %f", c.getWidthPoint())));
        // Measuring a String in Times
        BaseFont bf_times = BaseFont.createFont(
            "c:/windows/fonts/times.ttf", BaseFont.WINANSI, BaseFont.EMBEDDED);
        Font times = new Font(bf_times, 12);
        float width_times = bf_times.getWidthPoint(foobar, 12);
        c = new Chunk(foobar + ": " + width_times, times);
        document.add(new Paragraph(c));
        document.add(new Paragraph(String.format("Chunk width: %f", c.getWidthPoint())));
        document.add(Chunk.NEWLINE);
        // Ascent and descent of the String
        document.add(new Paragraph("Ascent Helvetica: "
                + bf_helv.getAscentPoint(foobar, 12)));
        document.add(new Paragraph("Ascent Times: "
                + bf_times.getAscentPoint(foobar, 12)));
        document.add(new Paragraph("Descent Helvetica: "
                + bf_helv.getDescentPoint(foobar, 12)));
        document.add(new Paragraph("Descent Times: "
                + bf_times.getDescentPoint(foobar, 12)));
        document.add(Chunk.NEWLINE);
        // Kerned text
        width_helv = bf_helv.getWidthPointKerned(foobar, 12);
        c = new Chunk(foobar + ": " + width_helv, helvetica);
        document.add(new Paragraph(c));
        // Drawing lines to see where the text is added
        PdfContentByte canvas = writer.getDirectContent();
        canvas.saveState();
        canvas.setLineWidth(0.05f);
        canvas.moveTo(400, 806);
        canvas.lineTo(400, 626);
        canvas.moveTo(508.7f, 806);
        canvas.lineTo(508.7f, 626);
        canvas.moveTo(280, 788);
        canvas.lineTo(520, 788);
        canvas.moveTo(280, 752);
        canvas.lineTo(520, 752);
        canvas.moveTo(280, 716);
        canvas.lineTo(520, 716);
        canvas.moveTo(280, 680);
        canvas.lineTo(520, 680);
        canvas.moveTo(280, 644);
        canvas.lineTo(520, 644);
        canvas.stroke();
        canvas.restoreState();
        // Adding text with PdfContentByte.showTextAligned()
        canvas.beginText();
        canvas.setFontAndSize(bf_helv, 12);
        canvas.showTextAligned(Element.ALIGN_LEFT, foobar, 400, 788, 0);
        canvas.showTextAligned(Element.ALIGN_RIGHT, foobar, 400, 752, 0);
        canvas.showTextAligned(Element.ALIGN_CENTER, foobar, 400, 716, 0);
        canvas.showTextAligned(Element.ALIGN_CENTER, foobar, 400, 680, 30);
        canvas.showTextAlignedKerned(Element.ALIGN_LEFT, foobar, 400, 644, 0);
        canvas.endText();
        // More lines to see where the text is added
        canvas.saveState();
        canvas.setLineWidth(0.05f);
        canvas.moveTo(200, 590);
        canvas.lineTo(200, 410);
        canvas.moveTo(400, 590);
        canvas.lineTo(400, 410);
        canvas.moveTo(80, 572);
        canvas.lineTo(520, 572);
        canvas.moveTo(80, 536);
        canvas.lineTo(520, 536);
        canvas.moveTo(80, 500);
        canvas.lineTo(520, 500);
        canvas.moveTo(80, 464);
        canvas.lineTo(520, 464);
        canvas.moveTo(80, 428);
        canvas.lineTo(520, 428);
        canvas.stroke();
        canvas.restoreState();
        // Adding text with ColumnText.showTextAligned()
        Phrase phrase = new Phrase(foobar, times);
        ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, 200, 572, 0);
        ColumnText.showTextAligned(canvas, Element.ALIGN_RIGHT, phrase, 200, 536, 0);
        ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, phrase, 200, 500, 0);
        ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, phrase, 200, 464, 30);
        ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, phrase, 200, 428, -30);
        // Chunk attributes
        c = new Chunk(foobar, times);
        c.setHorizontalScaling(0.5f);
        phrase = new Phrase(c);
        ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, 400, 572, 0);
        c = new Chunk(foobar, times);
        c.setSkew(15, 15);
        phrase = new Phrase(c);
        ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, 400, 536, 0);
        c = new Chunk(foobar, times);
        c.setSkew(0, 25);
        phrase = new Phrase(c);
        ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, 400, 500, 0);
        c = new Chunk(foobar, times);
        c.setTextRenderMode(PdfContentByte.TEXT_RENDER_MODE_STROKE, 0.1f, BaseColor.RED);
        phrase = new Phrase(c);
        ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, 400, 464, 0);
        c = new Chunk(foobar, times);
        c.setTextRenderMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE, 1, null);
        phrase = new Phrase(c);
        ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, 400, 428, -0);
        // step 5
        document.close();
    }
}
MovieTextInfo.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.chapter03;

import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.Date;
import java.util.List;

import com.lowagie.database.DatabaseConnection;
import com.lowagie.database.HsqldbConnection;
import com.lowagie.filmfestival.PojoFactory;
import com.lowagie.filmfestival.Screening;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.BaseColor;

/**
 * Draws a time table to the direct content using lines and simple shapes,
 * adding blocks representing a movies.
 */
public class MovieTextInfo extends MovieTimeBlocks {

    /** The resulting PDF. */
    public static final String RESULT = "results/part1/chapter03/calendar.pdf";

    /**
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws    DocumentException 
     * @throws    IOException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException {
    	// step 1
        Document document = new Document(PageSize.A4.rotate());
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        PdfContentByte over = writer.getDirectContent();
        PdfContentByte under = writer.getDirectContentUnder();
        try {
            DatabaseConnection connection = new HsqldbConnection("filmfestival");
            locations = PojoFactory.getLocations(connection);
            List days = PojoFactory.getDays(connection);
            List screenings;
            int d = 1;
            for (Date day : days) {
                drawTimeTable(under);
                drawTimeSlots(over);
                drawInfo(over);
                drawDateInfo(day, d++, over);
                screenings = PojoFactory.getScreenings(connection, day);
                for (Screening screening : screenings) {
                    drawBlock(screening, under, over);
                    drawMovieInfo(screening, over);
                }
                document.newPage();
            }
            connection.close();
        }
        catch(SQLException sqle) {
            sqle.printStackTrace();
            document.add(new Paragraph("Database error: " + sqle.getMessage()));
        }
        // step 5
        document.close();
    }
    
    /** The base font that will be used to write info on the calendar sheet. */
    protected BaseFont bf;
    
    /** A phrase containing a white letter "P" (for Press) */
    protected Phrase press;

    /** The different time slots. */
    public static String[] TIME =
        { "09:30", "10:00", "10:30", "11:00", "11:30", "12:00",
          "00:30", "01:00", "01:30", "02:00", "02:30", "03:00",
          "03:30", "04:00", "04:30", "05:00", "05:30", "06:00",
          "06:30", "07:00", "07:30", "08:00", "08:30", "09:00",
          "09:30", "10:00", "10:30", "11:00", "11:30", "12:00",
          "00:30", "01:00" };
    
    /**
     * Draws some text on every calendar sheet.
     * 
     */
    protected void drawInfo(PdfContentByte directcontent) {
        directcontent.beginText();
        directcontent.setFontAndSize(bf, 18);
        float x, y;
        x = (OFFSET_LEFT + WIDTH + OFFSET_LOCATION) / 2;
        y = OFFSET_BOTTOM + HEIGHT + 24;
        directcontent.showTextAligned(Element.ALIGN_CENTER,
            "FOOBAR FILM FESTIVAL", x, y, 0);
        x = OFFSET_LOCATION + WIDTH_LOCATION / 2f - 6;
        y = OFFSET_BOTTOM + HEIGHT_LOCATION;
        directcontent.showTextAligned(Element.ALIGN_CENTER,
            "The Majestic", x, y, 90);
        y = OFFSET_BOTTOM + HEIGHT_LOCATION * 4f;
        directcontent.showTextAligned(Element.ALIGN_CENTER,
            "Googolplex", x, y, 90);
        y = OFFSET_BOTTOM + HEIGHT_LOCATION * 7.5f;
        directcontent.showTextAligned(Element.ALIGN_CENTER,
            "Cinema Paradiso", x, y, 90);
        directcontent.setFontAndSize(bf, 12);
        x = OFFSET_LOCATION + WIDTH_LOCATION - 6;
        for (int i = 0; i < LOCATIONS; i++) {
            y = OFFSET_BOTTOM + ((8.5f - i) * HEIGHT_LOCATION);
            directcontent.showTextAligned(Element.ALIGN_CENTER,
                locations.get(i), x, y, 90);
        }
        directcontent.setFontAndSize(bf, 6);
        y = OFFSET_BOTTOM + HEIGHT + 1;
        for (int i = 0; i < TIMESLOTS; i++) {
            x = OFFSET_LEFT + (i * WIDTH_TIMESLOT);
            directcontent.showTextAligned(Element.ALIGN_LEFT,
                TIME[i], x, y, 45);
        }
        directcontent.endText();
    }
    /**
     * Draws some text on every calendar sheet.
     * 
     */
    protected void drawDateInfo(Date day, int d, PdfContentByte directcontent) {
        directcontent.beginText();
        directcontent.setFontAndSize(bf, 18);
        float x, y;
        x = OFFSET_LOCATION;
        y = OFFSET_BOTTOM + HEIGHT + 24;
        directcontent.showTextAligned(Element.ALIGN_LEFT,
                "Day " + d, x, y, 0);
        x = OFFSET_LEFT + WIDTH;
        directcontent.showTextAligned(Element.ALIGN_RIGHT,
                day.toString(), x, y, 0);
        directcontent.endText();
    }
    
    /**
     * Draws the info about the movie.
     * @throws DocumentException 
     */
    protected void drawMovieInfo(Screening screening, PdfContentByte directcontent)
        throws DocumentException {
        if (screening.isPress()) {
            Rectangle rect = getPosition(screening);
            ColumnText.showTextAligned(directcontent, Element.ALIGN_CENTER,
                    press, (rect.getLeft() + rect.getRight()) / 2,
                    rect.getBottom() + rect.getHeight() / 4, 0);
        }
    }
    
    /**
     * Constructor for the MovieCalendar class; initializes the base font object.
     * @throws IOException 
     * @throws DocumentException 
     */
    public MovieTextInfo() throws DocumentException, IOException {
        bf = BaseFont.createFont();
        Font f = new Font(bf, HEIGHT_LOCATION / 2);
        f.setColor(BaseColor.WHITE);
        press = new Phrase("P", f);
    }
    
    /**
     * Main method creating the PDF.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
        new MovieTextInfo().createPdf(RESULT);
    }
}
MovieCalendar.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.chapter03;

import java.io.IOException;

import com.lowagie.filmfestival.Screening;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;

/**
 * Draws a time table to the direct content using lines and simple shapes,
 * adding blocks representing a movies.
 */
public class MovieCalendar extends MovieTextInfo {

    /** The resulting PDF. */
    public static final String RESULT = "results/part1/chapter03/movie_calendar.pdf";
    
    /**
     * Draws the info about the movie.
     * @throws DocumentException 
     */
    protected void drawMovieInfo(Screening screening, PdfContentByte directcontent)
        throws DocumentException {
        super.drawMovieInfo(screening, directcontent);
        Rectangle rect = getPosition(screening);
        ColumnText column = new ColumnText(directcontent);
        column.setSimpleColumn(new Phrase(screening.getMovie().getMovieTitle()),
                rect.getLeft(), rect.getBottom(),
                rect.getRight(), rect.getTop(), 18, Element.ALIGN_CENTER);
        column.go();
    }
    
    /**
     * Constructor for the MovieCalendar class; initializes the base font object.
     * @throws IOException 
     * @throws DocumentException 
     */
    public MovieCalendar() throws DocumentException, IOException {
        super();
    }
    
    /**
     * Main method creating the PDF.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
        new MovieCalendar().createPdf(RESULT);
    }
}
MovieColumns1.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.chapter03;

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.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.Element;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.LineSeparator;

public class MovieColumns1 {

    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part1/chapter03/movie_columns1.pdf";
    
    /** Definition of two columns */
    public static final float[][] COLUMNS = {
        { 36, 36, 296, 806 } , { 299, 36, 559, 806 }
    };
    
    /**
     * 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));
        // step 3
        document.open();
        // step 4
        List movies = PojoFactory.getMovies(connection);
        ColumnText ct = new ColumnText(writer.getDirectContent());
        for (Movie movie : movies) {
            ct.addText(createMovieInformation(movie));
            ct.addText(Chunk.NEWLINE);
        }
        ct.setAlignment(Element.ALIGN_JUSTIFIED);
        ct.setExtraParagraphSpace(6);
        ct.setLeading(0, 1.2f);
        ct.setFollowingIndent(27);
        int linesWritten = 0;
        int column = 0;
        int status = ColumnText.START_COLUMN;
        while (ColumnText.hasMoreText(status)) {
            ct.setSimpleColumn(
                    COLUMNS[column][0], COLUMNS[column][1],
                    COLUMNS[column][2], COLUMNS[column][3]);
            ct.setYLine(COLUMNS[column][3]);
            status = ct.go();
            linesWritten += ct.getLinesWritten();
            column = Math.abs(column - 1);
            if (column == 0)
                document.newPage();
        }
        
        ct.addText(new Phrase("Lines written: " + linesWritten));
        ct.go();
        // step 5
        document.close();
        // Close the database connection
        connection.close();
    }
    
    /**
     * Creates a Phrase containing information about a movie.
     * @param    movie    the movie for which you want to create a Paragraph
     */
    public Phrase createMovieInformation(Movie movie) {
        Phrase p = new Phrase();
        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(new Chunk("Year: ", FilmFonts.BOLDITALIC));
        p.add(new Chunk(String.valueOf(movie.getYear()), FilmFonts.NORMAL));
        p.add(new Chunk(" Duration: ", FilmFonts.BOLDITALIC));
        p.add(new Chunk(String.valueOf(movie.getDuration()), FilmFonts.NORMAL));
        p.add(new Chunk(" minutes", FilmFonts.NORMAL));
        p.add(new LineSeparator(0.3f, 100, null, Element.ALIGN_CENTER, -2));
        return p;
    }

    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
        throws IOException, DocumentException, SQLException {
        new MovieColumns1().createPdf(RESULT);
    }
}
MovieColumns2.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.chapter03;

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

public class MovieColumns2 extends MovieColumns1 {

    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part1/chapter03/movie_columns2.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 {
        // 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));
        // step 3
        document.open();
        // step 4
        List movies = PojoFactory.getMovies(connection);
        ColumnText ct = new ColumnText(writer.getDirectContent());
        ct.setAlignment(Element.ALIGN_JUSTIFIED);
        ct.setExtraParagraphSpace(6);
        ct.setLeading(14);
        ct.setIndent(10);
        ct.setRightIndent(3);
        ct.setSpaceCharRatio(PdfWriter.NO_SPACE_CHAR_RATIO);
        int column = 0;
        int status = ColumnText.START_COLUMN;
        ct.setSimpleColumn(
            COLUMNS[column][0], COLUMNS[column][1],
            COLUMNS[column][2], COLUMNS[column][3]);
        for (Movie movie : movies) {
            ct.addText(createMovieInformation(movie));
            status = ct.go();
            if (ColumnText.hasMoreText(status)) {
                column = Math.abs(column - 1);
                if (column == 0)
                    document.newPage();
                ct.setSimpleColumn(
                    COLUMNS[column][0], COLUMNS[column][1],
                    COLUMNS[column][2], COLUMNS[column][3]);
                ct.setYLine(COLUMNS[column][3]);
                status = ct.go();
            }
        }
        // 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 MovieColumns2().createPdf(RESULT);
    }
}
MovieColumns3.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.chapter03;

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

public class MovieColumns3 extends MovieColumns1 {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter03/movie_columns3.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 {
        // 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));
        // step 3
        document.open();
        // step 4
        List movies = PojoFactory.getMovies(connection);
        ColumnText ct = new ColumnText(writer.getDirectContent());
        int column = 0;
        ct.setSimpleColumn(
            COLUMNS[column][0], COLUMNS[column][1],
            COLUMNS[column][2], COLUMNS[column][3]);
        int status = ColumnText.START_COLUMN;
        Phrase p;
        float y;
        for (Movie movie : movies) {
            y = ct.getYLine();
            p = createMovieInformation(movie);
            ct.addText(p);
            status = ct.go(true);
            if (ColumnText.hasMoreText(status)) {
                column = Math.abs(column - 1);
                if (column == 0)
                    document.newPage();
                ct.setSimpleColumn(
                    COLUMNS[column][0], COLUMNS[column][1],
                    COLUMNS[column][2], COLUMNS[column][3]);
                y = COLUMNS[column][3];
            }
            ct.setYLine(y);
            ct.setText(p);
            status = ct.go(false);
        }
        // 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 MovieColumns3().createPdf(RESULT);
    }
}
MovieColumns4.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.chapter03;

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.Element;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;

public class MovieColumns4 extends MovieColumns1 {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter03/movie_columns4.pdf";
    
    public static final float[][] LEFT =
        { { 36,806, 36,670, 108,670, 108,596, 36,596, 36,36 }, 
        { 299,806, 299,484, 336,484, 336,410, 299,410, 299,36 } };
    public static final float[][] RIGHT =
        { { 296,806, 296,484, 259,484, 259,410, 296,410, 296,36 },
        { 559,806, 559,246, 487,246, 487,172, 559,172, 559,36 } };
    
    /**
     * 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));
        // step 3
        document.open();
        // step 4
        PdfContentByte canvas = writer.getDirectContent();
        drawRectangles(canvas);
        List movies = PojoFactory.getMovies(connection);
        ColumnText ct = new ColumnText(canvas);
        ct.setAlignment(Element.ALIGN_JUSTIFIED);
        ct.setLeading(14);
        int column = 0;
        ct.setColumns(LEFT[column], RIGHT[column]);
        int status = ColumnText.START_COLUMN;
        Phrase p;
        float y;
        for (Movie movie : movies) {
            y = ct.getYLine();
            p = createMovieInformation(movie);
            ct.addText(p);
            status = ct.go(true);
            if (ColumnText.hasMoreText(status)) {
                column = Math.abs(column - 1);
                if (column == 0) {
                    document.newPage();
                    drawRectangles(canvas);
                }
                ct.setColumns(LEFT[column], RIGHT[column]);
                y = 806;
            }
            ct.setYLine(y);
            ct.setText(p);
            status = ct.go();
        }
        // step 5
        document.close();
        // Close the database connection
        connection.close();
    }
    
    /**
     * Draws three rectangles
     * @param canvas
     */
    public void drawRectangles(PdfContentByte canvas) {
        canvas.saveState();
        canvas.setGrayFill(0.9f);
        canvas.rectangle(33, 592, 72, 72);
        canvas.rectangle(263, 406, 72, 72);
        canvas.rectangle(491, 168, 72, 72);
        canvas.fillStroke();
        canvas.restoreState();
    }

    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args)
       throws IOException, DocumentException, SQLException {
        new MovieColumns4().createPdf(RESULT);
    }
}
ColumnMovies1.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.chapter03;

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

public class ColumnMovies1 {

    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part1/chapter03/column_movies1.pdf";
    /** Path to the resources. */
    public static final String RESOURCE
        = "resources/posters/%s.jpg";
    
    /** Definition of two columns */
    public static final float[][] COLUMNS = {
        { 36, 36, 224, 579 } , { 230, 36, 418, 579 },
        { 424, 36, 612, 579 } , { 618, 36, 806, 579 }
    };
    
    /**
     * 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(PageSize.A4.rotate());
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        List movies = PojoFactory.getMovies(connection);
        ColumnText ct = new ColumnText(writer.getDirectContent());
        int column = 0;
        ct.setSimpleColumn(
            COLUMNS[column][0], COLUMNS[column][1],
            COLUMNS[column][2], COLUMNS[column][3]);
        int status = ColumnText.START_COLUMN;
        float y;
        Image img;
        for (Movie movie : movies) {
            y = ct.getYLine();
            img = Image.getInstance(String.format(RESOURCE, movie.getImdb()));
            img.scaleToFit(80, 1000);
            addContent(ct, movie, img);
            status = ct.go(true);
            if (ColumnText.hasMoreText(status)) {
                column = (column + 1) % 4;
                if (column == 0)
                    document.newPage();
                ct.setSimpleColumn(
                    COLUMNS[column][0], COLUMNS[column][1],
                    COLUMNS[column][2], COLUMNS[column][3]);
                y = COLUMNS[column][3];
            }
            ct.setYLine(y);
            ct.setText(null);
            addContent(ct, movie, img);
            status = ct.go();
        }
        // step 5
        document.close();
        // Close the database connection
        connection.close();
    }
    
    /**
     * Add content to a ColumnText object.
     * @param ct the ColumnText object
     * @param movie a Movie object
     * @param img the poster of the image
     */
    public void addContent(ColumnText ct, Movie movie, Image img) {
        ct.addElement(img);
        ct.addElement(new Paragraph(movie.getTitle(), FilmFonts.BOLD));
        if (movie.getOriginalTitle() != null) {
            ct.addElement(new Paragraph(movie.getOriginalTitle(), FilmFonts.ITALIC));
        }
        ct.addElement(PojoToElementFactory.getDirectorList(movie));
        ct.addElement(PojoToElementFactory.getYearPhrase(movie));
        ct.addElement(PojoToElementFactory.getDurationPhrase(movie));
        ct.addElement(PojoToElementFactory.getCountryList(movie));
        ct.addElement(Chunk.NEWLINE);
    }

    /**
     * Main method.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args) throws IOException, DocumentException, SQLException {
        new ColumnMovies1().createPdf(RESULT);
    }
}
ColumnMovies2.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.chapter03;

import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

import part1.chapter02.StarSeparator;

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

public class ColumnMovies2 {

    /** The resulting PDF file. */
    public static final String RESULT = "results/part1/chapter03/column_movies2.pdf";
    
    /** Definition of two columns */
    public static final float[][] COLUMNS = {
        { 40, 36, 219, 579 } , { 234, 36, 414, 579 },
        { 428, 36, 608, 579 } , { 622, 36, 802, 579 }
    };
    
    /**
     * 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(PageSize.A4.rotate());
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        List movies = PojoFactory.getMovies(connection);
        ColumnText ct = new ColumnText(writer.getDirectContent());
        int column = 0;
        ct.setSimpleColumn(
            COLUMNS[column][0], COLUMNS[column][1],
            COLUMNS[column][2], COLUMNS[column][3]);
        int status = ColumnText.START_COLUMN;
        float y;
        for (Movie movie : movies) {
            y = ct.getYLine();
            addContent(ct, movie);
            status = ct.go(true);
            if (ColumnText.hasMoreText(status)) {
                column = (column + 1) % 4;
                if (column == 0)
                    document.newPage();
                ct.setSimpleColumn(
                    COLUMNS[column][0], COLUMNS[column][1],
                    COLUMNS[column][2], COLUMNS[column][3]);
                y = COLUMNS[column][3];
            }
            ct.setYLine(y);
            ct.setText(null);
            addContent(ct, movie);
            status = ct.go();
        }
        // step 5
        document.close();
        // Close the database connection
        connection.close();
    }
    
    /**
     * Adds info about a movie in a ColumnText object
     * @param ct A ColumnText object
     * @param movie A Movie POJO
     */
    public void addContent(ColumnText ct, Movie movie) {
        Paragraph p;
        p = new Paragraph(new Paragraph(movie.getTitle(), FilmFonts.BOLD));
        p.setAlignment(Element.ALIGN_CENTER);
        p.setSpacingBefore(16);
        ct.addElement(p);
        if (movie.getOriginalTitle() != null) {
            p = new Paragraph(movie.getOriginalTitle(), FilmFonts.ITALIC);
            p.setAlignment(Element.ALIGN_RIGHT);
            ct.addElement(p);
        }
        p = new Paragraph();
        p.add(PojoToElementFactory.getYearPhrase(movie));
        p.add(" ");
        p.add(PojoToElementFactory.getDurationPhrase(movie));
        p.setAlignment(Element.ALIGN_JUSTIFIED_ALL);
        ct.addElement(p);
        p = new Paragraph(new Chunk(new StarSeparator()));
        p.setSpacingAfter(12);
        ct.addElement(p);
    }

    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     * @throws SQLException
     */
    public static void main(String[] args) throws IOException, DocumentException, SQLException {
        new ColumnMovies2().createPdf(RESULT);
    }
}
ImageDirect.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.chapter03;

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

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.PdfWriter;

public class ImageDirect {

    /** The resulting PDF. */
    public static final String RESULT
        = "results/part1/chapter03/image_direct.pdf";
    /** The movie poster. */
    public static final String RESOURCE
        = "resources/img/loa.jpg";
    
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// step 1
        Document document
            = new Document(PageSize.POSTCARD, 30, 30, 30, 30);
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        writer.setCompressionLevel(0);
        // step 3
        document.open();
        // step 4
        Image img = Image.getInstance(RESOURCE);
        img.setAbsolutePosition((PageSize.POSTCARD.getWidth() - img.getScaledWidth()) / 2,
                (PageSize.POSTCARD.getHeight() - img.getScaledHeight()) / 2);
        writer.getDirectContent().addImage(img);
        Paragraph p = new Paragraph("Foobar Film Festival", new Font(FontFamily.HELVETICA, 22));
        p.setAlignment(Element.ALIGN_CENTER);
        document.add(p);
        // step 5
        document.close();
    }
}
ImageSkew.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.chapter03;

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

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;

public class ImageSkew {

    /** The resulting PDF. */
    public static final String RESULT = "results/part1/chapter03/image_skew.pdf";
    /** The movie poster. */
    public static final String RESOURCE = "resources/img/loa.jpg";

    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// step 1
        Document document = new Document(PageSize.POSTCARD.rotate());
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document,
                new FileOutputStream(RESULT));
        writer.setCompressionLevel(0);
        // step 3
        document.open();
        // step 4
        Image img = Image.getInstance(RESOURCE);
        // Add the image to the upper layer
        writer.getDirectContent().addImage(img,
            img.getWidth(), 0, 0.35f * img.getHeight(),
            0.65f * img.getHeight(), 30, 30);
        // step 5
        document.close();
    }
}
ImageInline.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.chapter03;

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

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;

public class ImageInline {

    /** The resulting PDF. */
    public static final String RESULT
        = "results/part1/chapter03/image_inline.pdf";
    /** The movie poster. */
    public static final String RESOURCE
        = "resources/img/loa.jpg";

    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
    	// step 1
        Document document = new Document(PageSize.POSTCARD, 30, 30, 30, 30);
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document,
                new FileOutputStream(RESULT));
        writer.setCompressionLevel(0);
        // step 3
        document.open();
        // step 4
        Image img = Image.getInstance(RESOURCE);
        img.setAbsolutePosition(
            (PageSize.POSTCARD.getWidth() - img.getScaledWidth()) / 2,
            (PageSize.POSTCARD.getHeight() - img.getScaledHeight()) / 2);
        writer.getDirectContent().addImage(img, true);
        // step 5
        document.close();
    }
}
MoviePosters.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.chapter03;

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.PageSize;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;

public class MoviePosters {
    /** The resulting PDF file. */
    public static final String RESULT
        = "results/part1/chapter03/movie_posters.pdf";
    /** Path to the resources. */
    public static final String RESOURCE
        = "resources/posters/%s.jpg";
    
    /**
     * 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 {
    	// Creates a database connection
        DatabaseConnection connection = new HsqldbConnection("filmfestival");    
        // step 1
        Document document = new Document(PageSize.A4);
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(filename));
        writer.setCompressionLevel(0);
        // step 3
        document.open();
        // step 4
        PdfContentByte canvas = writer.getDirectContent();
        // Create the XObject
        PdfTemplate celluloid = canvas.createTemplate(595, 84.2f);
        celluloid.rectangle(8, 8, 579, 68);
        for (float f = 8.25f; f < 581; f+= 6.5f) {
            celluloid.roundRectangle(f, 8.5f, 6, 3, 1.5f);
            celluloid.roundRectangle(f, 72.5f, 6, 3, 1.5f);
        }
        celluloid.setGrayFill(0.1f);
        celluloid.eoFill();
        // Write the XObject to the OutputStream
        writer.releaseTemplate(celluloid);
        // Add the XObject 10 times
        for (int i = 0; i < 10; i++) {
            canvas.addTemplate(celluloid, 0, i * 84.2f);
        }
        // Go to the next page
        document.newPage();
        // Add the XObject 10 times
        for (int i = 0; i < 10; i++) {
            canvas.addTemplate(celluloid, 0, i * 84.2f);
        }
        // Get the movies from the database
        List movies = PojoFactory.getMovies(connection);
        Image img;
        float x = 11.5f;
        float y = 769.7f;
        // Loop over the movies and add images
        for (Movie movie : movies) {
            img = Image.getInstance(String.format(RESOURCE, movie.getImdb()));
            img.scaleToFit(1000, 60);
            img.setAbsolutePosition(x + (45 - img.getScaledWidth()) / 2, y);
            canvas.addImage(img);
            x += 48;
            if (x > 578) {
                x = 11.5f;
                y -= 84.2f;
            }
        }
        // Go to the next page
        document.newPage();
        // Add the template using a different CTM
        canvas.addTemplate(celluloid, 0.8f, 0, 0.35f, 0.65f, 0, 600);
        // Wrap the XObject in an Image object
        Image tmpImage = Image.getInstance(celluloid);
        tmpImage.setAbsolutePosition(0, 480);
        document.add(tmpImage);
        // Perform transformations on the image
        tmpImage.setRotationDegrees(30);
        tmpImage.scalePercent(80);
        tmpImage.setAbsolutePosition(30, 500);
        document.add(tmpImage);
        // More transformations
        tmpImage.setRotation((float)Math.PI / 2);
        tmpImage.setAbsolutePosition(200, 300);
        document.add(tmpImage);
        // 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, SQLException, DocumentException {
        new MoviePosters().createPdf(RESULT);
    }
}
MovieTemplates.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.chapter03;

import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Date;
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.Screening;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;

/**
 * Draws a time table to the direct content using lines and simple shapes,
 * adding blocks representing a movies.
 */
public class MovieTemplates extends MovieCalendar {

    /** The resulting PDF. */
    public static final String RESULT
        = "results/part1/chapter03/movie_templates.pdf";

    /**
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws    DocumentException 
     * @throws    IOException
     */
    public void createPdf(String filename)
        throws IOException, DocumentException {
    	// step 1
        Document document = new Document(PageSize.A4.rotate());
        // step 2
        PdfWriter writer
            = PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        PdfContentByte over = writer.getDirectContent();
        PdfContentByte under = writer.getDirectContentUnder();
        try {
            DatabaseConnection connection = new HsqldbConnection("filmfestival");
            locations = PojoFactory.getLocations(connection);
            PdfTemplate t_under = under.createTemplate(
                    PageSize.A4.getHeight(), PageSize.A4.getWidth());
            drawTimeTable(t_under);
            PdfTemplate t_over = over.createTemplate(
                    PageSize.A4.getHeight(), PageSize.A4.getWidth());
            drawTimeSlots(t_over);
            drawInfo(t_over);
            List days = PojoFactory.getDays(connection);
            List screenings;
            int d = 1;
            for (Date day : days) {
                over.addTemplate(t_over, 0, 0);
                under.addTemplate(t_under, 0, 0);
                drawDateInfo(day, d++, over);
                screenings = PojoFactory.getScreenings(connection, day);
                for (Screening screening : screenings) {
                    drawBlock(screening, under, over);
                    drawMovieInfo(screening, over);
                }
                document.newPage();
            }
            connection.close();
        }
        catch(SQLException sqle) {
            sqle.printStackTrace();
            document.add(new Paragraph("Database error: " + sqle.getMessage()));
        }
        // step 5
        document.close();
    }
    
    /**
     * Constructs a MovieTemplates object.
     * @throws DocumentException
     * @throws IOException
     */
    public MovieTemplates() throws DocumentException, IOException {
        super();
    }
    
    /**
     * Main method creating the PDF.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException 
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
        new MovieTemplates().createPdf(RESULT);
    }
}
FestivalOpening.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 iTextSharp.text;
using iTextSharp.text.pdf;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class FestivalOpening : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      string RESOURCE = Utility.ResourcePosters;
      // step 1
      using (Document document = new Document(PageSize.POSTCARD, 30, 30, 30, 30)) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        // Create and add a Paragraph
        Paragraph p = new Paragraph(
          "Foobar Film Festival", 
          new Font(Font.FontFamily.HELVETICA, 22)
        );
        p.Alignment = Element.ALIGN_CENTER;
        document.Add(p);
        // Create and add an Image
        Image img = Image.GetInstance(Path.Combine(
          Utility.ResourceImage, "loa.jpg"
        ));
        img.SetAbsolutePosition(
          (PageSize.POSTCARD.Width - img.ScaledWidth) / 2,
          (PageSize.POSTCARD.Height - img.ScaledHeight) / 2
        );
        document.Add(img);
        // Now we go to the next page
        document.NewPage();
        document.Add(p);
        document.Add(img);
        // Add text on top of the image
        PdfContentByte over = writer.DirectContent;
        over.SaveState();
        float sinus = (float)Math.Sin(Math.PI / 60);
        float cosinus = (float)Math.Cos(Math.PI / 60);
        BaseFont bf = BaseFont.CreateFont();
        over.BeginText();
        over.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
        over.SetLineWidth(1.5f);
        over.SetRGBColorStroke(0xFF, 0x00, 0x00);
        over.SetRGBColorFill(0xFF, 0xFF, 0xFF);
        over.SetFontAndSize(bf, 36);
        over.SetTextMatrix(cosinus, sinus, -sinus, cosinus, 50, 324);
        over.ShowText("SOLD OUT");
        over.EndText();
        over.RestoreState();
        // Add a rectangle under the image
        PdfContentByte under = writer.DirectContentUnder;
        under.SaveState();
        under.SetRGBColorFill(0xFF, 0xD7, 0x00);
        under.Rectangle(5, 5,
          PageSize.POSTCARD.Width - 10, 
          PageSize.POSTCARD.Height - 10
        );
        under.Fill();
        under.RestoreState();        
      }
    }
// ===========================================================================
  }
}
GraphicsStateStack.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 iTextSharp.text;
using iTextSharp.text.pdf;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class GraphicsStateStack : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document(new Rectangle(200, 120))) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        PdfContentByte canvas = writer.DirectContent;
        // state 1:
        canvas.SetRGBColorFill(0xFF, 0x45, 0x00);
        // fill a rectangle in state 1
        canvas.Rectangle(10, 10, 60, 60);
        canvas.Fill();
        canvas.SaveState();
        // state 2;
        canvas.SetLineWidth(3);
        canvas.SetRGBColorFill(0x8B, 0x00, 0x00);
        // fill and stroke a rectangle in state 2
        canvas.Rectangle(40, 20, 60, 60);
        canvas.FillStroke();
        canvas.SaveState();
        // state 3:
        canvas.ConcatCTM(1, 0, 0.1f, 1, 0, 0);
        canvas.SetRGBColorStroke(0xFF, 0x45, 0x00);
        canvas.SetRGBColorFill(0xFF, 0xD7, 0x00);
        // fill and stroke a rectangle in state 3
        canvas.Rectangle(70, 30, 60, 60);
        canvas.FillStroke();
        canvas.RestoreState();
        // stroke a rectangle in state 2
        canvas.Rectangle(100, 40, 60, 60);
        canvas.Stroke();
        canvas.RestoreState();
        // fill and stroke a rectangle in state 1
        canvas.Rectangle(130, 50, 60, 60);
        canvas.FillStroke();        
      }
    }
// ===========================================================================
  }
}
MovieTimeTable.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 iTextSharp.text;
using iTextSharp.text.pdf;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class MovieTimeTable : IWriter {
// ===========================================================================
    public virtual void Write(Stream stream) {
      // step 1
      using (Document document = new Document(PageSize.A4.Rotate())) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        DrawTimeTable(writer.DirectContentUnder);
        DrawTimeSlots(writer.DirectContent);
      }
    }
// ---------------------------------------------------------------------------    
    /** The number of locations on our time table. */
    public const int LOCATIONS = 9;
    /** The number of time slots on our time table. */
    public const int TIMESLOTS = 32;
    
    /** The offset to the left of our time table. */
    public const float OFFSET_LEFT = 76;
    /** The width of our time table. */
    public const float WIDTH = 740;
    /** The offset from the bottom of our time table. */
    public const float OFFSET_BOTTOM = 36;
    /** The height of our time table */
    public const float HEIGHT = 504;
    
    /** The offset of the location bar next to our time table. */
    public const float OFFSET_LOCATION = 26;
    /** The width of the location bar next to our time table. */
    public const float WIDTH_LOCATION = 48;
    
    /** The height of a bar showing the movies at one specific location. */
    public static float HEIGHT_LOCATION = HEIGHT / LOCATIONS;
    /** The width of a time slot. */
    public static float WIDTH_TIMESLOT = WIDTH / TIMESLOTS;
// ---------------------------------------------------------------------------    
    /**
     * Draws the time table for a day at the film festival.
     * @param directcontent a canvas to which the time table has to be drawn.
     */
    protected void DrawTimeTable(PdfContentByte directcontent) {        
        directcontent.SaveState();
        directcontent.SetLineWidth(1.2f);
        float llx, lly, urx, ury;
        
        llx = OFFSET_LEFT;
        lly = OFFSET_BOTTOM;
        urx = OFFSET_LEFT + WIDTH;
        ury = OFFSET_BOTTOM + HEIGHT;
        directcontent.MoveTo(llx, lly);
        directcontent.LineTo(urx, lly);
        directcontent.LineTo(urx, ury);
        directcontent.LineTo(llx, ury);
        directcontent.ClosePath();
        directcontent.Stroke();
        
        llx = OFFSET_LOCATION;
        lly = OFFSET_BOTTOM;
        urx = OFFSET_LOCATION + WIDTH_LOCATION;
        ury = OFFSET_BOTTOM + HEIGHT;
        directcontent.MoveTo(llx, lly);
        directcontent.LineTo(urx, lly);
        directcontent.LineTo(urx, ury);
        directcontent.LineTo(llx, ury);
        directcontent.ClosePathStroke();
        
        directcontent.SetLineWidth(1);
        directcontent.MoveTo(
          OFFSET_LOCATION + WIDTH_LOCATION / 2, OFFSET_BOTTOM
        );
        directcontent.LineTo(
          OFFSET_LOCATION + WIDTH_LOCATION / 2, OFFSET_BOTTOM + HEIGHT
        );
        float y;
        for (int i = 1; i < LOCATIONS; i++) {
          y = OFFSET_BOTTOM + (i * HEIGHT_LOCATION);
          if (i == 2 || i == 6) {
            directcontent.MoveTo(OFFSET_LOCATION, y);
            directcontent.LineTo(OFFSET_LOCATION + WIDTH_LOCATION, y);
          }
          else {
            directcontent.MoveTo(OFFSET_LOCATION + WIDTH_LOCATION / 2, y);
            directcontent.LineTo(OFFSET_LOCATION + WIDTH_LOCATION, y);
          }
          directcontent.MoveTo(OFFSET_LEFT, y);
          directcontent.LineTo(OFFSET_LEFT + WIDTH, y);
        }
        directcontent.Stroke();
        directcontent.RestoreState();
    }
// ---------------------------------------------------------------------------    
    /**
     * Draws the time slots for a day at the film festival.
     * @param directcontent the canvas to which the time table has to be drawn.
     */
    protected void DrawTimeSlots(PdfContentByte directcontent) {
      directcontent.SaveState();
      float x;
      for (int i = 1; i < TIMESLOTS; i++) {
        x = OFFSET_LEFT + (i * WIDTH_TIMESLOT);
        directcontent.MoveTo(x, OFFSET_BOTTOM);
        directcontent.LineTo(x, OFFSET_BOTTOM + HEIGHT);
      }
      directcontent.SetLineWidth(0.3f);
      directcontent.SetColorStroke(BaseColor.GRAY);
      directcontent.SetLineDash(3, 1);
      directcontent.Stroke();
      directcontent.RestoreState();
    }    
// ===========================================================================
  }
}
MovieTimeBlocks.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 iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.html;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class MovieTimeBlocks : MovieTimeTable {
// ===========================================================================
    /** A list containing all the locations. */
    protected List locations;
// ---------------------------------------------------------------------------        
    public override void Write(Stream stream) {
      // step 1
      using (Document document = new Document(PageSize.A4.Rotate())) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        writer.CompressionLevel = 0;
        // step 3
        document.Open();
        // step 4
        PdfContentByte over = writer.DirectContent;
        PdfContentByte under = writer.DirectContentUnder;
        locations = PojoFactory.GetLocations();
        List days = PojoFactory.GetDays();
        List screenings;
        foreach (string day in days) {
          DrawTimeTable(under);
          DrawTimeSlots(over);
          screenings = PojoFactory.GetScreenings(day);
          foreach (Screening screening in screenings) {
            DrawBlock(screening, under, over);
          }
          document.NewPage();
        }
      }
    }
// ---------------------------------------------------------------------------        
    /**
     * Draws a colored block on the time table, corresponding with
     * the screening of a specific movie.
     * @param    screening    a screening POJO, contains a movie and a category
     * @param    under    the canvas to which the block is drawn
     */
    protected void DrawBlock(
      Screening screening, PdfContentByte under, PdfContentByte over
    ) {
      under.SaveState();
      BaseColor color = WebColors.GetRGBColor(
        "#" + screening.movie.entry.category.color
      );
      under.SetColorFill(color);
      Rectangle rect = GetPosition(screening);
      under.Rectangle(
        rect.Left, rect.Bottom, rect.Width, rect.Height
      );
      under.Fill();
      over.Rectangle(
        rect.Left, rect.Bottom, rect.Width, rect.Height
      );
      over.Stroke();
      under.RestoreState();
    }
// ---------------------------------------------------------------------------        
    /** The "offset time" for our calendar sheets. */
    // public static long TIME930 = 30600000L;
    public const long TIME930 = 34200000L;
    
    /** The width of one minute. */
    public readonly float MINUTE = WIDTH_TIMESLOT / 30f;
// ---------------------------------------------------------------------------        
    /**
     * Calculates the position of a rectangle corresponding with a screening.
     * @param    screening    a screening POJO, contains a movie
     * @return    a Rectangle
     */
    protected Rectangle GetPosition(Screening screening) {
      float llx, lly, urx, ury;
      // long minutesAfter930 = (screening.getTime().getTime() - TIME930) / 60000L;
      long minutesAfter930 = (
        Utility.GetMilliseconds(screening.Time) - TIME930
      ) / 60000L;
      llx = OFFSET_LEFT + (MINUTE * minutesAfter930);
      int location = locations.IndexOf(screening.Location) + 1;
      lly = OFFSET_BOTTOM + (LOCATIONS - location) * HEIGHT_LOCATION;
      urx = llx + MINUTE * screening.movie.Duration;
      ury = lly + HEIGHT_LOCATION;
      return new Rectangle(llx, lly, urx, ury);
    }
// ===========================================================================
  }
}
FoobarFilmFestival.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 iTextSharp.text;
using iTextSharp.text.pdf;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class FoobarFilmFestival : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      string RESOURCE = Utility.ResourcePosters;
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        Chunk c;
        String foobar = "Foobar Film Festival";
        // Measuring a String in Helvetica
        Font helvetica = new Font(Font.FontFamily.HELVETICA, 12);
        BaseFont bf_helv = helvetica.GetCalculatedBaseFont(false);
        float width_helv = bf_helv.GetWidthPoint(foobar, 12);
        c = new Chunk(foobar + ": " + width_helv, helvetica);
        document.Add(new Paragraph(c));
        document.Add(new Paragraph(string.Format(
          "Chunk width: {0}", c.GetWidthPoint()
        )));
        // Measuring a String in Times
        BaseFont bf_times = BaseFont.CreateFont(
          "c:/windows/fonts/times.ttf", 
          BaseFont.WINANSI, BaseFont.EMBEDDED
        );
        Font times = new Font(bf_times, 12);
        float width_times = bf_times.GetWidthPoint(foobar, 12);
        c = new Chunk(foobar + ": " + width_times, times);
        document.Add(new Paragraph(c));
        document.Add(new Paragraph(String.Format(
          "Chunk width: {0}", c.GetWidthPoint()
        )));
        document.Add(Chunk.NEWLINE);
        // Ascent and descent of the String
        document.Add(new Paragraph(
          "Ascent Helvetica: " + bf_helv.GetAscentPoint(foobar, 12)
        ));
        document.Add(new Paragraph(
          "Ascent Times: " + bf_times.GetAscentPoint(foobar, 12)
        ));
        document.Add(new Paragraph(
          "Descent Helvetica: " + bf_helv.GetDescentPoint(foobar, 12)
        ));
        document.Add(new Paragraph(
          "Descent Times: " + bf_times.GetDescentPoint(foobar, 12)
        ));
        document.Add(Chunk.NEWLINE);
        // Kerned text
        width_helv = bf_helv.GetWidthPointKerned(foobar, 12);
        c = new Chunk(foobar + ": " + width_helv, helvetica);
        document.Add(new Paragraph(c));
        // Drawing lines to see where the text is added
        PdfContentByte canvas = writer.DirectContent;
        canvas.SaveState();
        canvas.SetLineWidth(0.05f);
        canvas.MoveTo(400, 806);
        canvas.LineTo(400, 626);
        canvas.MoveTo(508.7f, 806);
        canvas.LineTo(508.7f, 626);
        canvas.MoveTo(280, 788);
        canvas.LineTo(520, 788);
        canvas.MoveTo(280, 752);
        canvas.LineTo(520, 752);
        canvas.MoveTo(280, 716);
        canvas.LineTo(520, 716);
        canvas.MoveTo(280, 680);
        canvas.LineTo(520, 680);
        canvas.MoveTo(280, 644);
        canvas.LineTo(520, 644);
        canvas.Stroke();
        canvas.RestoreState();
        // Adding text with PdfContentByte.ShowTextAligned()
        canvas.BeginText();
        canvas.SetFontAndSize(bf_helv, 12);
        canvas.ShowTextAligned(Element.ALIGN_LEFT, foobar, 400, 788, 0);
        canvas.ShowTextAligned(Element.ALIGN_RIGHT, foobar, 400, 752, 0);
        canvas.ShowTextAligned(Element.ALIGN_CENTER, foobar, 400, 716, 0);
        canvas.ShowTextAligned(Element.ALIGN_CENTER, foobar, 400, 680, 30);
        canvas.ShowTextAlignedKerned(Element.ALIGN_LEFT, foobar, 400, 644, 0);
        canvas.EndText();
        // More lines to see where the text is added
        canvas.SaveState();
        canvas.SetLineWidth(0.05f);
        canvas.MoveTo(200, 590);
        canvas.LineTo(200, 410);
        canvas.MoveTo(400, 590);
        canvas.LineTo(400, 410);
        canvas.MoveTo(80, 572);
        canvas.LineTo(520, 572);
        canvas.MoveTo(80, 536);
        canvas.LineTo(520, 536);
        canvas.MoveTo(80, 500);
        canvas.LineTo(520, 500);
        canvas.MoveTo(80, 464);
        canvas.LineTo(520, 464);
        canvas.MoveTo(80, 428);
        canvas.LineTo(520, 428);
        canvas.Stroke();
        canvas.RestoreState();
        // Adding text with ColumnText.ShowTextAligned()
        Phrase phrase = new Phrase(foobar, times);
        ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT, phrase, 200, 572, 0);
        ColumnText.ShowTextAligned(canvas, Element.ALIGN_RIGHT, phrase, 200, 536, 0);
        ColumnText.ShowTextAligned(canvas, Element.ALIGN_CENTER, phrase, 200, 500, 0);
        ColumnText.ShowTextAligned(canvas, Element.ALIGN_CENTER, phrase, 200, 464, 30);
        ColumnText.ShowTextAligned(canvas, Element.ALIGN_CENTER, phrase, 200, 428, -30);
        // Chunk attributes
        c = new Chunk(foobar, times);
        c.SetHorizontalScaling(0.5f);
        phrase = new Phrase(c);
        ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT, phrase, 400, 572, 0);
        c = new Chunk(foobar, times);
        c.SetSkew(15, 15);
        phrase = new Phrase(c);
        ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT, phrase, 400, 536, 0);
        c = new Chunk(foobar, times);
        c.SetSkew(0, 25);
        phrase = new Phrase(c);
        ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT, phrase, 400, 500, 0);
        c = new Chunk(foobar, times);
        c.SetTextRenderMode(PdfContentByte.TEXT_RENDER_MODE_STROKE, 0.1f, BaseColor.RED);
        phrase = new Phrase(c);
        ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT, phrase, 400, 464, 0);
        c = new Chunk(foobar, times);
        c.SetTextRenderMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE, 1, null);
        phrase = new Phrase(c);
        ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT, phrase, 400, 428, -0);        
      }
    }
// ===========================================================================
  }
}
MovieTextInfo.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 iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.html;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

/**
 * Draws a time table to the direct content using lines and simple shapes,
 * adding blocks representing a movies.
 */
namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class MovieTextInfo : MovieTimeBlocks {
// ===========================================================================
    public override void Write(Stream stream) {
      // step 1
      using (Document document = new Document(PageSize.A4.Rotate())) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        PdfContentByte over = writer.DirectContent;
        PdfContentByte under = writer.DirectContentUnder;
        locations = PojoFactory.GetLocations();
        List days = PojoFactory.GetDays();
        List screenings;
        int d = 1;
        foreach (string day in days) {
          DrawTimeTable(under);
          DrawTimeSlots(over);
          DrawInfo(over);
          DrawDateInfo(day, d++, over);
          screenings = PojoFactory.GetScreenings(day);
          foreach (Screening screening in screenings) {
            DrawBlock(screening, under, over);
            DrawMovieInfo(screening, over);
          }
          document.NewPage();
        }
      }
    }
// ---------------------------------------------------------------------------        
    /** The base font that will be used to write info on the calendar sheet. */
    protected BaseFont bf;
    
    /** A phrase containing a white letter "P" (for Press) */
    protected Phrase press;

    /** The different time slots. */
    public readonly String[] TIME = { 
      "09:30", "10:00", "10:30", "11:00", "11:30", "12:00",
      "00:30", "01:00", "01:30", "02:00", "02:30", "03:00",
      "03:30", "04:00", "04:30", "05:00", "05:30", "06:00",
      "06:30", "07:00", "07:30", "08:00", "08:30", "09:00",
      "09:30", "10:00", "10:30", "11:00", "11:30", "12:00",
      "00:30", "01:00" 
    };
// ---------------------------------------------------------------------------           
    /**
     * Draws some text on every calendar sheet.
     * 
     */
    protected void DrawInfo(PdfContentByte directcontent) {
      directcontent.BeginText();
      directcontent.SetFontAndSize(bf, 18);
      float x, y;
      x = (OFFSET_LEFT + WIDTH + OFFSET_LOCATION) / 2;
      y = OFFSET_BOTTOM + HEIGHT + 24;
      directcontent.ShowTextAligned(
        Element.ALIGN_CENTER,
        "FOOBAR FILM FESTIVAL", x, y, 0
      );
      x = OFFSET_LOCATION + WIDTH_LOCATION / 2f - 6;
      y = OFFSET_BOTTOM + HEIGHT_LOCATION;
      directcontent.ShowTextAligned(
        Element.ALIGN_CENTER,
        "The Majestic", x, y, 90
      );
      y = OFFSET_BOTTOM + HEIGHT_LOCATION * 4f;
      directcontent.ShowTextAligned(
        Element.ALIGN_CENTER,
        "Googolplex", x, y, 90
      );
      y = OFFSET_BOTTOM + HEIGHT_LOCATION * 7.5f;
      directcontent.ShowTextAligned(
        Element.ALIGN_CENTER,
        "Cinema Paradiso", x, y, 90
      );
      directcontent.SetFontAndSize(bf, 12);
      x = OFFSET_LOCATION + WIDTH_LOCATION - 6;
      for (int i = 0; i < LOCATIONS; i++) {
        y = OFFSET_BOTTOM + ((8.5f - i) * HEIGHT_LOCATION);
        directcontent.ShowTextAligned(
          Element.ALIGN_CENTER,
          locations[i], x, y, 90
        );
      }
      directcontent.SetFontAndSize(bf, 6);
      y = OFFSET_BOTTOM + HEIGHT + 1;
      for (int i = 0; i < TIMESLOTS; i++) {
        x = OFFSET_LEFT + (i * WIDTH_TIMESLOT);
        directcontent.ShowTextAligned(
          Element.ALIGN_LEFT,
          TIME[i], x, y, 45
        );
      }
      directcontent.EndText();
    }
// ---------------------------------------------------------------------------            
    /**
     * Draws some text on every calendar sheet.
     * 
     */
    protected void DrawDateInfo(string day, int d, PdfContentByte directcontent) {
      directcontent.BeginText();
      directcontent.SetFontAndSize(bf, 18);
      float x, y;
      x = OFFSET_LOCATION;
      y = OFFSET_BOTTOM + HEIGHT + 24;
      directcontent.ShowTextAligned(
        Element.ALIGN_LEFT,
        "Day " + d, x, y, 0
      );
      x = OFFSET_LEFT + WIDTH;
      directcontent.ShowTextAligned(
        Element.ALIGN_RIGHT,
        day, x, y, 0
      );
      directcontent.EndText();
    }
// ---------------------------------------------------------------------------            
    /**
     * Draws the info about the movie.
     * @throws DocumentException 
     */
    protected virtual void DrawMovieInfo(
      Screening screening, PdfContentByte directcontent
    ) {
      // if (true) {
      if (screening.Press) {
        Rectangle rect = GetPosition(screening);
        ColumnText.ShowTextAligned(
          directcontent, 
          Element.ALIGN_CENTER,
          press, (rect.Left + rect.Right) / 2,
          rect.Bottom + rect.Height / 4, 0
        );
      }
    }
// ---------------------------------------------------------------------------            
    /**
     * Constructor for the MovieCalendar class; initializes the base font object.
     * @throws IOException 
     * @throws DocumentException 
     */
    public MovieTextInfo() {
      bf = BaseFont.CreateFont();
      Font f = new Font(bf, HEIGHT_LOCATION / 2);
      f.Color = BaseColor.WHITE;
      press = new Phrase("P", f);
    }
// ===========================================================================
  }
}
MovieCalendar.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 iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.html;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class MovieCalendar : MovieTextInfo {
// ===========================================================================
    /**
     * Draws the info about the movie.
     * @throws DocumentException 
     */
    protected override void DrawMovieInfo(
      Screening screening, PdfContentByte directcontent
    ) {
      base.DrawMovieInfo(screening, directcontent);
      Rectangle rect = GetPosition(screening);
      ColumnText column = new ColumnText(directcontent);
      column.SetSimpleColumn(
        new Phrase(screening.movie.Title),
        rect.Left, rect.Bottom,
        rect.Right, rect.Top, 18, Element.ALIGN_CENTER
      );
      column.Go();
    }
// ---------------------------------------------------------------------------            
    /**
     * Constructor for the MovieCalendar class; initializes the base font object.
     * @throws IOException 
     * @throws DocumentException 
     */
    public MovieCalendar() : base() {  }
// ===========================================================================
  }
}
MovieColumns1.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 iTextSharp.text.pdf.draw;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class MovieColumns1 : IWriter {
// ===========================================================================
    public virtual void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        IEnumerable movies = PojoFactory.GetMovies();
        ColumnText ct = new ColumnText(writer.DirectContent);
        foreach (Movie movie in movies) {
          ct.AddText(CreateMovieInformation(movie));
          ct.AddText(Chunk.NEWLINE);
        }
        ct.Alignment = Element.ALIGN_JUSTIFIED;
        ct.ExtraParagraphSpace = 6;
        ct.SetLeading(0, 1.2f);
        ct.FollowingIndent = 27;
        int linesWritten = 0;
        int column = 0;
        // iText-ONLY, 'Initial value of the status' => 0
        // iTextSharp **DOES NOT** include this member variable
        // int status = ColumnText.START_COLUMN;
        int status = 0;
        while (ColumnText.HasMoreText(status)) {
          ct.SetSimpleColumn(
            COLUMNS[column][0], COLUMNS[column][1],
            COLUMNS[column][2], COLUMNS[column][3]
          );
          ct.YLine = COLUMNS[column][3];
          status = ct.Go();
          linesWritten += ct.LinesWritten;
          column = Math.Abs(column - 1);
          if (column == 0) document.NewPage();
        }
        
        ct.AddText(new Phrase("Lines written: " + linesWritten));
        ct.Go();
      }
    }
// ---------------------------------------------------------------------------    
    /** Definition of two columns */
    public readonly float[][] COLUMNS = {
      new float[] { 36, 36, 296, 806 },
      new float[] { 299, 36, 559, 806 }
    };
// ---------------------------------------------------------------------------    
    /**
     * Creates a Phrase containing information about a movie.
     * @param    movie    the movie for which you want to create a Paragraph
     */
    public Phrase CreateMovieInformation(Movie movie) {
      Phrase p = new Phrase();
      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(new Chunk("Year: ", FilmFonts.BOLDITALIC));
      p.Add(new Chunk(movie.Year.ToString(), FilmFonts.NORMAL));
      p.Add(new Chunk(" Duration: ", FilmFonts.BOLDITALIC));
      p.Add(new Chunk(movie.Duration.ToString(), FilmFonts.NORMAL));
      p.Add(new Chunk(" minutes", FilmFonts.NORMAL));
      p.Add(new LineSeparator(0.3f, 100, null, Element.ALIGN_CENTER, -2));
      return p;
    }    
// ===========================================================================
  }
}
MovieColumns2.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 iTextSharp.text.pdf.draw;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class MovieColumns2 : MovieColumns1 {
// ===========================================================================
    public override void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        ColumnText ct = new ColumnText(writer.DirectContent) {
          Alignment = Element.ALIGN_JUSTIFIED, ExtraParagraphSpace = 6, 
          Leading = 14, Indent = 10, RightIndent = 3,
          SpaceCharRatio = PdfWriter.NO_SPACE_CHAR_RATIO
        };
        int column = 0;
        // iText-ONLY, 'Initial value of the status' => 0
        // iTextSharp **DOES NOT** include this member variable
        // int status = ColumnText.START_COLUMN;
        int status = 0;
        ct.SetSimpleColumn(
          COLUMNS[column][0], COLUMNS[column][1],
          COLUMNS[column][2], COLUMNS[column][3]
        );
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
          ct.AddText(CreateMovieInformation(movie));
          status = ct.Go();
          if (ColumnText.HasMoreText(status)) {
            column = Math.Abs(column - 1);
            if (column == 0) {
              document.NewPage();
            }
            ct.SetSimpleColumn(
              COLUMNS[column][0], COLUMNS[column][1],
              COLUMNS[column][2], COLUMNS[column][3]
            );
            ct.YLine = COLUMNS[column][3];
            status = ct.Go();
          }
        }
      }
    }
// ===========================================================================
  }
}
MovieColumns3.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 iTextSharp.text.pdf.draw;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class MovieColumns3 : MovieColumns1 {
// ===========================================================================
    public override void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        ColumnText ct = new ColumnText(writer.DirectContent);
        int column = 0;
        ct.SetSimpleColumn(
          COLUMNS[column][0], COLUMNS[column][1],
          COLUMNS[column][2], COLUMNS[column][3]
        );
        // iText-ONLY, 'Initial value of the status' => 0
        // iTextSharp **DOES NOT** include this member variable
        // int status = ColumnText.START_COLUMN;
        int status = 0;
        Phrase p;
        float y;        
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
          y = ct.YLine;
          p = CreateMovieInformation(movie);        
          ct.AddText(p);
          status = ct.Go(true);
          if (ColumnText.HasMoreText(status)) {
            column = Math.Abs(column - 1);
            if (column == 0) {
              document.NewPage();
            }
            ct.SetSimpleColumn(
              COLUMNS[column][0], COLUMNS[column][1],
              COLUMNS[column][2], COLUMNS[column][3]
            );
            y = COLUMNS[column][3];
          }
          ct.YLine = y;
          ct.SetText(p);
          status = ct.Go(false);
        }
      }
    }
// ===========================================================================
  }
}
MovieColumns4.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 iTextSharp.text.pdf.draw;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class MovieColumns4 : MovieColumns1 {
// ===========================================================================
    public override void Write(Stream stream) {
      // step 1
      using (Document document = new Document()) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        PdfContentByte canvas = writer.DirectContent;
        DrawRectangles(canvas);
        ColumnText ct = new ColumnText(canvas);
        ct.Alignment = Element.ALIGN_JUSTIFIED;
        ct.Leading = 14;
        int column = 0;
        ct.SetColumns(
          new float[] { 36,806, 36,670, 108,670, 108,596, 36,596, 36,36 }, 
          new float[] { 296,806, 296,484, 259,484, 259,410, 296,410, 296,36 }
        ); 
        ct.SetColumns(LEFT[column], RIGHT[column] );
        // ct.SetColumns(LEFT[column], RIGHT[column]);
        // iText-ONLY, 'Initial value of the status' => 0
        // iTextSharp **DOES NOT** include this member variable
        // int status = ColumnText.START_COLUMN;
        int status = 0;
        Phrase p;
        float y;
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
          y = ct.YLine;
          p = CreateMovieInformation(movie);
          ct.AddText(p);
          status = ct.Go(true);
          if (ColumnText.HasMoreText(status)) {
            column = Math.Abs(column - 1);
            if (column == 0) {
              document.NewPage();
              DrawRectangles(canvas);
            }
            ct.SetColumns(LEFT[column], RIGHT[column]);
            y = 806;
          }
          ct.YLine = y;
          ct.SetText(p);
          status = ct.Go();
        }        
      }
    }
// ---------------------------------------------------------------------------    
    public readonly float[][] LEFT = { 
      new float[] { 36,806, 36,670, 108,670, 108,596, 36,596, 36,36 }, 
      new float[] { 299,806, 299,484, 336,484, 336,410, 299,410, 299,36 } 
    };
    public readonly float[][] RIGHT = { 
      new float[] { 296,806, 296,484, 259,484, 259,410, 296,410, 296,36 },
      new float[] { 559,806, 559,246, 487,246, 487,172, 559,172, 559,36 } 
    };
// ---------------------------------------------------------------------------    
    /**
     * Draws three rectangles
     * @param canvas
     */
    public void DrawRectangles(PdfContentByte canvas) {
      canvas.SaveState();
      canvas.SetGrayFill(0.9f);
      canvas.Rectangle(33, 592, 72, 72);
      canvas.Rectangle(263, 406, 72, 72);
      canvas.Rectangle(491, 168, 72, 72);
      canvas.FillStroke();
      canvas.RestoreState();
    }    
// ===========================================================================
  }
}
ColumnMovies1.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.Chapter03 {
  public class ColumnMovies1 : IWriter {
// ===========================================================================
    public readonly string RESOURCE = Utility.ResourcePosters;
    /** Definition of two columns */
    public readonly float[,] COLUMNS = new float[,]  {
      { 36, 36, 224, 579 } , { 230, 36, 418, 579 },
      { 424, 36, 612, 579 } , { 618, 36, 806, 579 }
    };
// ---------------------------------------------------------------------------
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document(PageSize.A4.Rotate())) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        ColumnText ct = new ColumnText(writer.DirectContent);
        int column = 0;
        ct.SetSimpleColumn(
          COLUMNS[column,0], COLUMNS[column,1],
          COLUMNS[column,2], COLUMNS[column,3]
        );
        // iText-ONLY, 'Initial value of the status' => 0
        // iTextSharp **DOES NOT** include this member variable
        // int status = ColumnText.START_COLUMN;
        int status = 0;
        float y;
        Image img;
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
          y = ct.YLine;
          img = Image.GetInstance(
            Path.Combine(RESOURCE, movie.Imdb + ".jpg")
          );
          img.ScaleToFit(80, 1000);
          AddContent(ct, movie, img);
          status = ct.Go(true);
          if (ColumnText.HasMoreText(status)) {
            column = (column + 1) % 4;
            if (column == 0) {
              document.NewPage();
            }
            ct.SetSimpleColumn(
              COLUMNS[column, 0], COLUMNS[column, 1],
              COLUMNS[column, 2], COLUMNS[column, 3]
            );
            y = COLUMNS[column, 3];
          }
          ct.YLine = y;
          ct.SetText(null);
          AddContent(ct, movie, img);
          status = ct.Go();
        }
      }
    }
// ---------------------------------------------------------------------------    
    /**
     * Add content to a ColumnText object.
     * @param ct the ColumnText object
     * @param movie a Movie object
     * @param img the poster of the image
     */
    public void AddContent(ColumnText ct, Movie movie, Image img) {
      ct.AddElement(img);
      ct.AddElement(new Paragraph(movie.Title, FilmFonts.BOLD));
      if (!string.IsNullOrEmpty(movie.OriginalTitle)) {
        ct.AddElement(new Paragraph(movie.OriginalTitle, FilmFonts.ITALIC));
      }
      ct.AddElement(PojoToElementFactory.GetDirectorList(movie));
      ct.AddElement(PojoToElementFactory.GetYearPhrase(movie));
      ct.AddElement(PojoToElementFactory.GetDurationPhrase(movie));
      ct.AddElement(PojoToElementFactory.GetCountryList(movie));
      ct.AddElement(Chunk.NEWLINE);
    }    
// ===========================================================================
  }
}
ColumnMovies2.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;
using kuujinbo.iTextInAction2Ed.Chapter02;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class ColumnMovies2 : IWriter {
// ===========================================================================
    /** Definition of two columns */
    public readonly float[,] COLUMNS = new float[,]  {
      { 40, 36, 219, 579 } , { 234, 36, 414, 579 },
      { 428, 36, 608, 579 } , { 622, 36, 802, 579 }
    };
// ---------------------------------------------------------------------------
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document(PageSize.A4.Rotate())) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        ColumnText ct = new ColumnText(writer.DirectContent);
        int column = 0;
        ct.SetSimpleColumn(
          COLUMNS[column,0], COLUMNS[column,1],
          COLUMNS[column,2], COLUMNS[column,3]
        );
        // iText-ONLY, 'Initial value of the status' => 0
        // iTextSharp **DOES NOT** include this member variable
        // int status = ColumnText.START_COLUMN;
        int status = 0;
        float y;
        IEnumerable movies = PojoFactory.GetMovies();
        foreach (Movie movie in movies) {
          y = ct.YLine;
          AddContent(ct, movie);
          status = ct.Go(true);
          if (ColumnText.HasMoreText(status)) {
            column = (column + 1) % 4;
            if (column == 0) {
              document.NewPage();
            }
            ct.SetSimpleColumn(
              COLUMNS[column, 0], COLUMNS[column, 1],
              COLUMNS[column, 2], COLUMNS[column, 3]
            );
            y = COLUMNS[column, 3];
          }
          ct.YLine = y;
          ct.SetText(null);
          AddContent(ct, movie);
          status = ct.Go();
        }
      }
    }
// ---------------------------------------------------------------------------    
    /**
     * Add content to a ColumnText object.
     * @param ct the ColumnText object
     * @param movie a Movie object
     * @param img the poster of the image
     */
    public void AddContent(ColumnText ct, Movie movie) {
      Paragraph p;
      p = new Paragraph(new Paragraph(movie.Title, FilmFonts.BOLD));
      p.Alignment = Element.ALIGN_CENTER;
      p.SpacingBefore = 16;
      ct.AddElement(p);
      if (!string.IsNullOrEmpty(movie.OriginalTitle)) {
        p = new Paragraph(movie.OriginalTitle, FilmFonts.ITALIC);
        p.Alignment = Element.ALIGN_RIGHT;
        ct.AddElement(p);
      }
      p = new Paragraph();
      p.Add(PojoToElementFactory.GetYearPhrase(movie));
      p.Add(" ");
      p.Add(PojoToElementFactory.GetDurationPhrase(movie));
      p.Alignment = Element.ALIGN_JUSTIFIED_ALL;
      ct.AddElement(p);
      p = new Paragraph(new Chunk(new StarSeparator()));
      p.SpacingAfter = 12;
      ct.AddElement(p);
  }    
// ===========================================================================
  }
}
ImageDirect.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 iTextSharp.text;
using iTextSharp.text.pdf;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class ImageDirect : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document(PageSize.POSTCARD, 30, 30, 30, 30)) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        writer.CompressionLevel = 0;
        // step 3
        document.Open();
        // step 4
        Image img = Image.GetInstance(Path.Combine(
          Utility.ResourceImage, "loa.jpg"
        ));
        img.SetAbsolutePosition(
          (PageSize.POSTCARD.Width - img.ScaledWidth) / 2,
          (PageSize.POSTCARD.Height - img.ScaledHeight) / 2
        );
        writer.DirectContent.AddImage(img);
        Paragraph p = new Paragraph(
          "Foobar Film Festival", 
          new Font(Font.FontFamily.HELVETICA, 22)
        );
        p.Alignment = Element.ALIGN_CENTER;
        document.Add(p);        
      }
    }
// ===========================================================================
  }
}
ImageSkew.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 iTextSharp.text;
using iTextSharp.text.pdf;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class ImageSkew : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document(PageSize.POSTCARD.Rotate())) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        writer.CompressionLevel = 0;
        // step 3
        document.Open();
        // step 4
        Image img = Image.GetInstance(Path.Combine(
          Utility.ResourceImage, "loa.jpg"
        ));
        // Add the image to the upper layer
        writer.DirectContent.AddImage(
          img,
          img.Width, 0, 0.35f * img.Height,
          0.65f * img.Height, 30, 30
        );
      }
    }
// ===========================================================================
  }
}
ImageInline.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 iTextSharp.text;
using iTextSharp.text.pdf;

namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class ImageInline : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document(PageSize.POSTCARD, 30, 30, 30, 30)) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        writer.CompressionLevel = 0;
        // step 3
        document.Open();
        // step 4
        Image img = Image.GetInstance(Path.Combine(
          Utility.ResourceImage, "loa.jpg"
        ));
        img.SetAbsolutePosition(
          (PageSize.POSTCARD.Width - img.ScaledWidth) / 2,
          (PageSize.POSTCARD.Height - img.ScaledHeight) / 2
        );
        writer.DirectContent.AddImage(img, true);
      }
    }
// ===========================================================================
  }
}
MoviePosters.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.Chapter03 {
  public class MoviePosters : IWriter {
// ===========================================================================
    public void Write(Stream stream) {
      // step 1
      using (Document document = new Document(PageSize.A4)) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        writer.CompressionLevel = 0;
        // step 3
        document.Open();
        // step 4
        PdfContentByte canvas = writer.DirectContent;
        // Create the XObject
        PdfTemplate celluloid = canvas.CreateTemplate(595, 84.2f);
        celluloid.Rectangle(8, 8, 579, 68);
        for (float f = 8.25f; f < 581; f+= 6.5f) {
          celluloid.RoundRectangle(f, 8.5f, 6, 3, 1.5f);
          celluloid.RoundRectangle(f, 72.5f, 6, 3, 1.5f);
        }
        celluloid.SetGrayFill(0.1f);
        celluloid.EoFill();
        // Write the XObject to the OutputStream
        writer.ReleaseTemplate(celluloid);
        // Add the XObject 10 times
        for (int i = 0; i < 10; i++) {
          canvas.AddTemplate(celluloid, 0, i * 84.2f);
        }
        // Go to the next page
        document.NewPage();
        // Add the XObject 10 times
        for (int i = 0; i < 10; i++) {
          canvas.AddTemplate(celluloid, 0, i * 84.2f);
        }
        // Get the movies from the database
        IEnumerable movies = PojoFactory.GetMovies();
        Image img;
        float x = 11.5f;
        float y = 769.7f;
        string RESOURCE = Utility.ResourcePosters;
        // Loop over the movies and add images
        foreach (Movie movie in movies) {
          img = Image.GetInstance(Path.Combine(RESOURCE, movie.Imdb + ".jpg"));
          img.ScaleToFit(1000, 60);
          img.SetAbsolutePosition(x + (45 - img.ScaledWidth) / 2, y);
          canvas.AddImage(img);
          x += 48;
          if (x > 578) {
            x = 11.5f;
            y -= 84.2f;
          }
        }
        // Go to the next page
        document.NewPage();
        // Add the template using a different CTM
        canvas.AddTemplate(celluloid, 0.8f, 0, 0.35f, 0.65f, 0, 600);
        // Wrap the XObject in an Image object
        Image tmpImage = Image.GetInstance(celluloid);
        tmpImage.SetAbsolutePosition(0, 480);
        document.Add(tmpImage);
        // Perform transformations on the image
        tmpImage.RotationDegrees = 30;
        tmpImage.ScalePercent(80);
        tmpImage.SetAbsolutePosition(30, 500);
        document.Add(tmpImage);
        // More transformations
        tmpImage.Rotation = (float)Math.PI / 2;
        tmpImage.SetAbsolutePosition(200, 300);
        document.Add(tmpImage);
      }
    }
// ===========================================================================
  }
}
MovieTemplates.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 iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.html;
using kuujinbo.iTextInAction2Ed.Intro_1_2;

/**
 * Draws a time table to the direct content using lines and simple shapes,
 * adding blocks representing a movies.
 */
namespace kuujinbo.iTextInAction2Ed.Chapter03 {
  public class MovieTemplates : MovieCalendar {
// ===========================================================================
    public override void Write(Stream stream) {
      // step 1
      using (Document document = new Document(PageSize.A4.Rotate())) {
        // step 2
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // step 3
        document.Open();
        // step 4
        PdfContentByte over = writer.DirectContent;
        PdfContentByte under = writer.DirectContentUnder;
        locations = PojoFactory.GetLocations();
        PdfTemplate t_under = under.CreateTemplate(
          PageSize.A4.Height, PageSize.A4.Width
        );
        DrawTimeTable(t_under);
        PdfTemplate t_over = over.CreateTemplate(
          PageSize.A4.Height, PageSize.A4.Width
        );
        DrawTimeSlots(t_over);
        DrawInfo(t_over);        
        List days = PojoFactory.GetDays();
        List screenings;
        int d = 1;
        foreach (string day in days) {
          over.AddTemplate(t_over, 0, 0);
          under.AddTemplate(t_under, 0, 0);
          DrawDateInfo(day, d++, over);
          screenings = PojoFactory.GetScreenings(day);
          foreach (Screening screening in screenings) {
            DrawBlock(screening, under, over);
            DrawMovieInfo(screening, over);
          }
          document.NewPage();
        }
      }
    }
// ---------------------------------------------------------------------------            
    /**
     * Constructor MovieTemplates object.
     */
    public MovieTemplates() : base() {  }
// ===========================================================================
  }
}
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