iText 7: Making the Switch

Posted by

Our company does a lot of work with PDFs.  Our core product generates them, combines them, converts other files to them, and plenty of other things.  We practically have to make them walk on their hind legs and recite the Bhagavad Gita. Last year, iText released a completely re-written version their venerable PDF libraries and I have been tasked with making all the code changes to our product for the switch from iText 5 to iText 7.  In the words of Danny Glover, “I’m getting too old for this [expletive deleted]”.

Actually, when I did the initial analysis to see how big a job it was going to be, it didn’t seem too bad.  It is a total rewrite, but it looked like all the functionality remained.  It had just been redistributed between packages or to entirely new packages and maybe a few classes and methods were renamed.  No big deal.

Ha! Ha ha ha ha! And furthermore, ha!

Don’t get me wrong.  I really like the way they re-wrote it and there are some pretty decent examples out there.  Many were written by Bruno Lowagie himself who is not, contrary to all sense, a character in the Mario Brothers franchise.  But if you weren’t an iText genius before starting this, your task is practically double because you have to understand the old way before migrating to the new way, that is, if you want any continuity whatsoever across major revs of your own product.

For example, this:

becomes this:

The first thing I did was to remove the iText 5 jar (singular) from my project and replace it with the iText 7 jars (so, so many jars – but that’s a good thing, trust me) just to see what would break.  It was an absolute massacre. My code is bleeding to death!

So what I’m trying to do is boil the changes down to some core guiding principles that might smooth the road a bit.  I’ll be posting these Eureka! moments as they occur.

Here’s a closer look at some of the code above.  Here, we are defining default style elements for specific usages of iText’s PdfCell object (now Cell in iText 7). The differences really remind me of HTML vs. CSS.

iText 5

// in iText 5, we declare multiple style-related objects that are
// customized for our purposes.
private static Font HEADER_CELL_FONT = new Font(Font.FontFamily.COURIER, 10, Font.BOLD);
public static BaseColor HEADER_CELL_BG_COLOR = new BaseColor(210,215,255);

// Then create a HeaderCell class and apply these style elements.
// This is the default for the locally defined HeaderCell object
// in our implementation.
public static class HeaderCell extends PdfPCell{

    public HeaderCell(String string) throws BadElementException {
        super(new DGHeaderFontParagraph(string));
        setBorderColor(BaseColor.LIGHT_GRAY);
        setBackgroundColor(HEADER_CELL_BG_COLOR);
    }
}

// We use HeaderCell in a variety of different ways so we override
// it here.
// We also override the constructors so we can create default
// behaviors depending on the type of object passed.
public static class DGPdfHeaderCell extends PdfPCell{

    public DGPdfHeaderCell(Phrase arg0) {
        super(arg0);
        setBorderColor(BaseColor.LIGHT_GRAY);
        setBackgroundColor(HEADER_CELL_BG_COLOR);
    }

    public DGPdfHeaderCell(Image arg0) {
        super(arg0, true);
        setBorderColor(BaseColor.WHITE);
        setBackgroundColor(HEADER_CELL_BG_COLOR);
    }

    public DGPdfHeaderCell() {
        super();
        setBackgroundColor(HEADER_CELL_BG_COLOR);
        setBorderColor(BaseColor.LIGHT_GRAY);
    }

    public DGPdfHeaderCell(String arg0) {
        super(new Paragraph(arg0, HEADER_CELL_FONT));
        setBackgroundColor(HEADER_CELL_BG_COLOR);
        setBorderColor(BaseColor.LIGHT_GRAY);
    }
}

iText 7

// In iText 7, we create a single style object that is analagous
// to a CSS class.
// It can be applied anywhere. It can also be overriden anywhere for
// special cases.
public static Style HEADER_CELL_STYLE = null;

static {
    try {

    HEADER_CELL_STYLE = new Style()
        .setFont(PdfFontFactory.createFont(FontConstants.COURIER_BOLD))
        .setFontSize(10)
        .setBorder(new SolidBorder(Color.LIGHT_GRAY, 1))
        .setBackgroundColor(Color.BLUE);
    } catch (IOException e) {
        // Shhhh... nobody saw nuttin'.
    }
}

// Once again, we override the iText Cell object (formerly called
// the PdfCell object). This will be the default.
// We could apply a Style object here and it would be used by every
// implementation of the HeaderCell object.
// Or, as you can see further down, we can apply it when we override
// this class allowing us to customize the style based on the
// constructor.
public static class HeaderCell extends Cell {

public HeaderCell(String string) {
    super();
    add(new DGHeaderFontParagraph(string));
}

}

// Just as in iText 5, we override our own HeaderCell class so we
// can apply default behaviors based on our usage.
public static class DGPdfHeaderCell extends HeaderCell{

    public DGPdfHeaderCell(Text arg0) {
        super();
        add(new Paragraph(arg0).addStyle(HEADER_CELL_STYLE));
    }

    public DGPdfHeaderCell(Image arg0) {
        super();
        add(arg0.setAutoScale(true));
    }

    public DGPdfHeaderCell() {
        super();
        addStyle(HEADER_CELL_STYLE);
    }

    public DGPdfHeaderCell(String arg0) {
        super();
        add(new Paragraph(arg0).addStyle(HEADER_CELL_STYLE));
    }
}

So, to restate, I’m just trying to get to a handle on the key concepts.  Style is a good place to start.  It makes an awful lot of sense to encapsulate the style elements in a single object rather than have a host of font, color, and other constants.

Next, we’ll be coming to grips with the new PDF hierarchy.  Strap in, it’s going to get bumpy.

Share on Facebook0Tweet about this on TwitterShare on LinkedIn0Share on Yummly0Pin on Pinterest0Email this to someone

Leave a Reply

Your email address will not be published.