We've been working for a couple of weeks of elapsed time now, we figure, so it's time to focus a bit more on end to end. How about a draft PDF report?

We Need a Paper Report

Our vision of the product is that we offer a service: people submit their paper targets full of holes, and we produce a report on paper, full of important information about their shotgun, and their shooting. We are not contemplating a Web-based product at this time – just paper.

We figure that we would like our output to be recorded in PDF. When we finish a client’s analysis, his results will be saved as a PDF file and sent to him on paper. We can file the PDF to reproduce his results as of the time of creation, even if the program evolves.

We discussed two ways of producing the necessary report. One would be to draw everything using the Graphics2D functionality, and then direct it to a PDF virtual printer, which we happen to have. I took the role of arguing for this option, despite some serious difficulties, such as pagination and paragraph wrapping. Chet was arguing that “somewhere out there” there were probably Java-based libraries for creating PDF, and these imaginary libraries would be vastly easier to use than whatever we might code up ourselves.

It’s hard to beat magic when all you have on your side is reality, and I was pretty easily convinced that if any of these magical libraries were any good at all, they’d be better than what we could do by hand. Chet took on the task of finding one. The good news is, he was successful.

iText

Chet found a package called iText, by Bruno Lowagie and Paulo Soares. He even brought a little spike example to Borders. And Borders even had a copie of the iText book, by Bruno, so we bought it and got to work.

There is a lot of very complex capability in iText, but fortunately all we will need is some text paragraphs, some images, and possibly some images in tables. iText understand all of these things, and all the fonts and spacing a person could possibly want. We even managed to get our entire document written on one line, at one point, just in case we need that.

There’s a very nice iText tutorial on the Web, which we had downloaded to our machines, so between that, the book, and some creative reasoning, we were able to get a simple example running pretty quickly. Here’s a picture of the PDF, linked to the file itself:

image

Your keen eye will note that we figured out how to do paragraphs that are centered, spaced, and justified (textually, if not with regard to content) and that word wrap works just fine. We got a picture to show up, and as you’ll see in a moment, it is even scaled and has a border. This is enough to do almost everything we want, and aside from the rather boring and repetitive character of the text, it’s a good, if simple example of what we actually need to do.

The code looks like this:

package com.hendricksonxp.patterning.spike;

import java.awt.Color;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.FontFactory;
import com.lowagie.text.Image;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfWriter;

public class PdfExperiment {

    final static String outputFolder = "Output\\";
    private static Document document;

    public static void main(String[] args) 
      throws DocumentException, MalformedURLException, IOException {
        document = new Document(PageSize.LETTER, 50, 50, 50, 50);
        PdfWriter.getInstance(document, new FileOutputStream(outputFolder + "ITextTest.pdf"));
        document.open();
        Paragraph para = new Paragraph("First page of the document.");
        para.setAlignment(Element.ALIGN_CENTER);
        document.add(para);
        para = new Paragraph("Some more text on the first page with different 
        color and font type. We are now going to drone on and on and on and 
        on and on and on and on and on and on and on and on and on and on and 
        on and on and on and on and on and on and on and on and on and on and 
        on and on and on and on and on and on and on and on and on and on and 
        on and on and on and on and on and on and on and on and on and on and 
        on and on and on and on and on with an eye to finding out what 
        happens in the paragraph operations.", 
                FontFactory.getFont(FontFactory.HELVETICA, 12, Font.NORMAL, Color.BLUE));
        para.setFirstLineIndent(36f);
        para.setSpacingAfter(14f);
        para.setAlignment(Element.ALIGN_JUSTIFIED);
        para.setLeading(14f);
        document.add(para);
        para = new Paragraph("Some more text on the first page with different 
        color and font type. We are now going to drone on and on and on and 
        on and on and on and on and on and on and on and on and on and on and 
        on and on and on and on and on and on and on and on and on and on and 
        on and on and on and on and on and on and on and on and on and on and 
        on and on and on and on and on and on and on and on and on and on and 
        on and on and on and on and on with an eye to finding out what 
        happens in the paragraph operations.", 
                FontFactory.getFont(FontFactory.HELVETICA, 12, Font.NORMAL, Color.BLUE));

        para.setExtraParagraphSpace(20f);
        para.setAlignment(Element.ALIGN_JUSTIFIED);
        para.setLeading(14f);
        document.add(para);

        Image jpg = Image.getInstance(outputFolder + "patternImage.jpg");
        jpg.scalePercent((float) 12);
        jpg.setBorderColor(Color.BLACK);
        jpg.setBorder(15);
        jpg.setBorderWidth(10.0f);
        document.add(jpg);
        document.add(new Paragraph("Some more text below the image."));
        document.close();
    }
}

There’s a bit of a story to go with the border of the picture. The final code is highlighted above. The first few values we tried, we hadn’t found any document information. (In fact, I think we still haven’t.) We tried various values for setBorder, and nothing happened. We added in setBorderColor, which we found in the “intellisense”, and that changed things. Now when we put numbers into setBorder, we would get apparently random selections of top, bottom, left, right. That triggered the thought: It’s a bit field! So we put in 15, and sure enough all the borders appeared. We then figured that we could control the width, in pixels or points or something, with setBorderWidth(). We still don’t really know what we were doing, but we do know enough to make it work!

End to End? Not Quite. Business Value? Yes.

This report is pretty boring, but it shows the customer a sample that includes everything we’ve been told so far about the output. Clearly we’ll want more interesting text, and I personally hope we ditch the full justification and go to right justification only. We’ll want more pictures, in various scales, and that’s an easy continuation of what we’ve done.

I think we’d like a nice table of contents, showing thumbnails of the pictures that will occur on the pages, and that will require some use of tables, or some equivalent, and perhaps some forward references to page numbers, which I think the software can support.

The very first report we did looks enough like a page from the final reports to give our customer the confidence that we can do what he wants, and gives us the confidence that we can do so, and even estimate the work, as well.

Not bad at all for two hours’ work. We celebrated with a pair of Jimmy John’s #5 sandwiches, The Vito. There was a high school group there, and a member of the calculus club had a t-shirt: Don’t drink and derive.

Remember that.