logo

Embedding Fonts In Java PDF-Creating Agents

Yesterday I talked about using Web Fonts to overcome the limitations of being restricted to the limited set of fonts available to web developers. Today I'll talk about over-coming the even more limited set of fonts available when creating PDF documents.

When you create a PDF with the likes of iText you're normally limited to the choice of Courier, Helvetica and Times New Roman. Helvetica is probably the default choice, but it's borrrrrring.

Let's use Source Sans Pro instead! Here's an example of a PDF using Source Sans Pro.

image

So, so, so much nicer than Helvetica.

If you want to try it out, you can create a Domino-driven PDF with the above font embedded in it by using this demo form.

How To Embed Fonts

How do you go about embedded the font for use with a Domino Java agent? Well, first thing you do is download the font. It doesn't have to be Source Sans Pro, but assuming you want it then download the "fonts only" ZIP from Sourceforge and extract to your PC.

Now, open the Java Agent you use for creating PDFs and click the Import dropdown button and choose to import a Resource. Browse to the folder of fonts and select the ones you want to use in your PDF.

image

When you're done the Agent will list the font files in the "Res" section, as below:

image

With the font files stored in the Agent you can load them at runtime and create a BaseFont based on them.

Here's the code that load the fonts as two BaseFonts (one for regular fonts and one for bold). The code then uses the BaseFonts to create some useable Fonts.

//Regular base font
BaseFont bf = BaseFont.createFont("SourceSansPro-Regular.otf",
    BaseFont.WINANSI,
    BaseFont.EMBEDDED,
    false,
    getResourceAsByteArray("SourceSansPro-Regular.otf"),
    null);

//Bold base font
BaseFont bfb = BaseFont.createFont("SourceSansPro-Bold.otf",
    BaseFont.WINANSI,
    BaseFont.EMBEDDED,
    false,
    getResourceAsByteArray("SourceSansPro-Semibold.otf"),
    null);

//A collection of fonts (based upon our base fonts) for re-use throughout the code!
Font defaultFont = new Font(bf, 12);
Font headerFont = new Font(bfb, 18);
Font tinyFont = new Font(bf, 9);
Font tinyFontBoldAndWhite = new Font(bfb, 9, Font.NORMAL, Color.WHITE);

It's those last four Font objects that we'll use in our code to specify the font for any PDF objects we add to our iText PDF Document.

Loading Resources

Notice in the above code that there was a call to a method call getResourceAsByteArray(). This simply gets a stream on the font file we stored in the Agent and converts it to a byte[] array that the BaseFont class can use.

Here's what that method looks like.

public static byte[] getResourceAsByteArray(String resourceName) throws Exception{
    InputStream is = this.getClass().getResourceAsStream("/" + resourceName);
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();

    int nRead;
    byte[] data = new byte[16384];

    while ((nRead = is.read(data, 0, data.length)) != -1) {
        buffer.write(data, 0, nRead);
    }
    buffer.flush();

    return buffer.toByteArray();
}

The key to the above code is the getClass().getResourceAsStream() call which is what actually loads the file from the Resources section of the Agent.

Using The Fonts

Now that we've defined our Font objects we can use them in the code when added iText objects such as Paragraph to the document.

Paragraph myParagraph = new Paragraph( doc.getItemValueString("Title") , headerFont);
myParagraph.setAlignment(Element.ALIGN_CENTER);
document.add( myParagraph );

Anchor anchor = new Anchor(
    new Chunk( "This is a link back to the document which created this PDF!",
        new Font(bf, 10, Font.UNDERLINE, new Color(0, 0, 255) )
    )
);

It's as simple as that. And the results are worth it.

Trade-Off

As with using Web Fonts there's a file size trade-off to consider. Embedding fonts in a PDF can easily add 50KB to its size. And that's per font-style. So, if you want Regular, Bold and Italic, it's three times that size.

You could of course just embed the Regular font and force it to act like bold or italic, but, as with the web, you don't get the same results.

Comments

  1. Very timely. I've been working on a tool that uses the user name to generate a watermark with transparency and a pitch angle. The standard font doesn't scale well when you try to make it 100 pt tall, so it gets very blocky. The trick I had to use was to start off with the image for the watermark 300 pt tall and then resize the image a couple of times. This automatically smooths the edges, much to my delight, as the resizing function uses some interpolation rules. Simply using a BaseFont set up with a large font face would be a less memory intensive upgrade to this process.

    Thank you, once again, sir Jake. You have been knighted by know, surely?

    1. From the British Embassy website:

      The Most Excellent Order of the British Empire (1917) is awarded mainly to civilians and service personnel for public service or other distinctions and has a military and a civil division. Ranks in the Order are Knight or Dame Grand Cross (GBE), Knight or Dame Commander (KBE or DBE), Commander (CBE), Officer (OBE) and Member (MBE).

      If I'm not mistaken, private individuals can be nominated for Knighthood to this order, and your decade of contributions to the advancement of the art of making due with otherwise horrible tools is certainly a service to the crown and humanity.

      Show the rest of this thread

  2. Did u ever try PDFBox? With its Apache license it is less of an development headache

      • avatar
      • Jake Howlett
      • Wed 15 Aug 2012 03:56 PM

      It would take a better reason than licencing to move me off iText. It just works. And well.

      I knows there's a lot of confusion over iText licencing since version 5. But I only ever use version 2.x which doesn't fall fowl. I hope. See, there you go, confusion. Maybe PDFBox would be better ;-)

      Show the rest of this thread

    • avatar
    • Rob Darwin
    • Wed 15 Aug 2012 01:33 PM

    Would this still work if the font files lived in /jvm/lib/ext to avoid the overhead of detaching from the agent each run?

      • avatar
      • Jake Howlett
      • Wed 15 Aug 2012 03:55 PM

      Not using the getResource() method but if you can put them on the server's disk (anywhere) then you can create a BaseFont from a File object.

      As I understand it though. The Agent's content is stored on disk anyway (is it?) and it's not got to load it from inside the NSF each time. Or does it?

    • avatar
    • Jakes dad
    • Thu 16 Aug 2012 03:53 PM

    if Jake became a 'Sir' then that would make Karen

    a 'Lady' I'm lost for words.~(;-(

  3. Nice..Does it put any more pressure on the JVM?

      • avatar
      • Jake Howlett
      • Fri 17 Aug 2012 04:13 AM

      Undoubtedly.

      Show the rest of this thread

Your Comments

Name:
E-mail:
(optional)
Website:
(optional)
Comment:


About This Page

Written by Jake Howlett on Wed 15 Aug 2012

Share This Page

# ( ) '

Comments

The most recent comments added:

Skip to the comments or add your own.

You can subscribe to an individual RSS feed of comments on this entry.

Let's Get Social


About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »

More Content