Big Faceless releases PDF Library 2.17.1

BFO have just released a new update to their PDF Library, the first for a few months. Here we describe a few features that are in the new release in a bit more detail.

Integrating Logging messages with the viewer

Our logging framework is a thin wrapper around whichever of Log4J or java.util.logging is configured, which means it's essentially a functional interface. Log messages can be sent at any time, from any thread, and are not easily linked to an object like a PDF - for starters, most of the warning messages in the API are generated during load, before the PDF object itself is created.

So when a customer asked to be able to display warning messages in our PDF viewer, this was a bit of a challenge. The result is our WarningNotifier feature, which is a bit of an odd fit due to the architectural difficulties we faced. It's disabled by default, and although functional we view it as a starting point for customers to extend upon rather than a standalone feature.

To use it, add an instance of of this class (or a subclass) to the list of features you pass into the PDFViewer constructor. Warnings will be displayed in a translucent window in the bottom-right of the PDFViewer, and will expire automatically or when clicked on. If you want to tweak the appearance or implement features we don't currently have (throttling the number of messages or hiding duplicates, for example) then you just need to extend the WarningNotifier class to provide your own implementation of this method:

    /**
     * This method is called when a warning event can be associated with a JComponent.
     * It is always be called on the Swing EventDispatchThread.
     *
     * @param component the component identified as interested in this warning
     * @param source the source object which triggered the warning for this JComponent by being
     * registered. This may be any type of object, for example a PDF, a PDFReader or a Thread.
     * @param code the unique warning code
     * @param message the warning message
     * @param throwable the stack trace associated with that warning, if applicable.
     * @param thread the Thread on which the warning originated
     */
    public void warningEvent(JComponent component, Object source, String code, String message, Throwable throwable, Thread thread) {
    }
   

Barcode Positioning

Our barcodes are drawn in a PDFCanvas, and that canvas includes the amount of surrounding whitespace required by each barcode specification, as well as the text.

If your application requires more precise control over the position then the new BarCode.getContentRectangle method will give you the position within that barcode of the code itself.

Changes for JAWS Screen Reader

If you need to create structured PDF documents for accessibility, we've been able to do that for a while. However a customer recently noticed that hyperlinks in our PDFs weren't being correctly identified by the JAWS Screen Reader. This small observation resulted in a rather large rewrite, and now structured PDFs created with our API will give the correct results when being read with assistive technologies.

Painting a PDF page to your own Graphics2D?

Sometimes the only way to get the information you need is to pass in your own Graphics2D object to our PagePainter and then try to interpret the results - if you're trying to determine a visual bounding box of the page, for example. Anyone doing this will rapidly discover that text in a PDF isn't always drawn as text: sometimes we'll create a Shape and fill that instead. We do this due to limitations in the java.awt.Font API which make it impossible to create your own subclass and use it with methods like Graphics2D.drawString, but it does make identifying a character from a regular vector graphic object much harder.

To make this a little easier we have two new RenderingHints which we set on the Graphics2D object. The KEY_SHAPETEXT_FONT has a value which is the PDFFont that is in use, and the KEY_SHAPETEXT_STRING has a value which is the text about to be displayed. So you could conceivably extend Graphics2D with code that looked like this:

    @Override public void setRenderingHint(RenderingHints.Key key, Object value) {
        if (key == PagePainter.KEY_SHAPETEXT_STRING) {
            String text = (String)value;
            if (text != null) {
                // All future graphics operations on this Graphics2D relate to the
                // display of this text value.
            } else {
                // All future graphics operations do not relate to text, but come
                // from vector operations within the PDF page.
            }
        } else {
            super.setRenderingHint(key, value);
        }
    }
    

Other changes

There are a lot of other small changes to the API, some of which might affect you - so please do have a look at our Changelog for more detail.