JPEG2000, Java and PDF

Summary for the impatient

Upgrade to bfopdf 2.22.2 or later, and add the bfopdf-jj2000.jar included in our package to your CLASSPATH. Ensure you remove other versions of the JJ2000 classes from your classpath.

The Background

The JPEG 2000 compression algorithm was designed in 2000 as a successor to the venerable JPEG algorithm. It's designed to compress continuous tone images like photographs, and supports both a lossy and lossless variation.

It's a very complex algorithm and uptake is still relatively limited. The main Java implementation is known as JJ2000 and was written by a team from Swiss Federal Institute of Technology-EPFL, Ericsson Radio Systems AB and Canon Research Centre France S.A during 1999-2000 as part of the development of the original JPEG2000 specification. Since then it has moved home several times over the years; as the API design outside of the core classes didn't lend itself to easy integration, several variations of the code have come into existance.

Prior to release 2.22.2, we were recommending the original Sun repackaging (in 2009) and the updated version of the Sun package after it moved to Github (in 2016). Both of these packaged the decoder as part of the JAI extensions for java image decoding, which adds an awful lot of baggage.

So in May 2018 we set ourselves the task of repackaging the JJ2000, removing the dependency on JAI and trying to fix some of the rendering bugs. The source code for this result is at https://github.com/faceless2/jpeg2000, and we now distribute a compiled version of this with the PDF Library in the Jar "bfopdf-jj2000.jar".

If this Jar is in your classpath, we'll use it. If you have the original Github package (the Jars are normally called something like jai-imageio-jpeg2000-1.3.1-SNAPSHOT.jar and jai-image-code-1.3.1-SNAPHOT.jar), then they will continue to work, but you'll miss out on a couple of changes:

  • We fixed two rendering bugs; one visible as a "black splodge" on some images, and one resulting in slightly reduced rendering quality for some images (and large errors if the image is indexed).
  • Memory footprint has been reduced, although the gains are usually fairly marginal.
  • We can access the lower-resolution version of the image if available. For very large images stored as a single tile, this can significantly reduce memory usage - particularly in the viewer, where decoding the thumbnail image now takes just a fraction of the original memory.

So we recommend you remove them and use the bfopdf-jj2000.jar instead. Be aware that these classes are bundled with other APIs too, so if the JJ2000 classes fail to load due to classloading issues, try running Java with java -verbose:class, which will show all the classes that are loaded and which Jar they come from. If you see the "jj2000" package in a Jar, remove it from your classpath.

What about patents and licensing?

Aspects of the JPEG2000 algorithm are patented, however the owners of those patents have agreed to waive their right to collect royalty or license fees in relation to their use as part of the JPEG2000 standard. As with all algorithms, it is possible that other patents exist that cover some aspects which no-one is aware of. However as none have appeared in the 18 years since it was published that looks like a very remote possibility. Of course you should get your own advice on this, and if you are concerned then you can always just delete the "bfopdf-jj2000.jar" file from your system. The API will continue to work, without the ability to decode JPEG2000 compressed image data.

The license for the JJ2000 classes can be seen at https://github.com/faceless2/jpeg2000/blob/master/LICENSE-JJ2000.txt, which is reproduced in the LICENSE.txt file included with our API as required.

What about encoding?

Not yet. It's working but Acrobat XI and DC, alone, are unable to decode the images, while earler versions of Acrobat and literally every other product we tested are fine. If we can get it working it will be included in a future update.

The original text of this article remains below for posterity

The JPEG 2000 compression algorithm was designed in 2000 as a successor to the venerable JPEG algorithm, which dates back to 1992. It's designed to compress "continuous tone" images such as photographs, and supports both a lossy (like JPEG) and a lossless format. We covered a bit on image compression in a previous article.

Adobe added support for JPEG 2000 compressed images in Acrobat 5.0, (calling it JPX compression), and it's becoming more and more common to find PDF Documents containing photographic images compressed with this algorithm.

The Problem

Java supports JPEG 2000, but this capability is not included with the JDK by default. This only becomes a problem when you try to display (or convert to bitmap) a PDF containing a JPEG 2000 compressed image: if support isn't available, you'll see the Exception:

 PDF WARNING SP2: Unable to create image: caused by java.io.IOException: No JPEG2000 decoding support in ImageIO package

The image in question will be a gray square instead

The Solution (Updated for 2016)

The original version of this article from 2009 referred to some links which have long since disappeared from the web. If you have the Jars from that era, they will still work, but if not then a version of the code still exists. As best as we can tell it is functionally equivalent to the original release, so there is no point in moving from one to the other: if you have a working solution with the original Jars, don't change anything.

The current resting place for the code is in these two Github repositories: the core files and the JPEG2000 files. The class hierarchy is slightly different to the original codebase, but our API will handle either.

If you're familiar with Github and Maven then building from source is probably the easiest route. You will need the following two Jars in your classpath:

  • jai-imageio-core-NNN.jar, from the jai-imageio-core package. At the time of writing you can download a pre-built binary directly from Bintray.
  • jai-imageio-jpeg2000-NNN.jar, from the jai-imageio-jpeg2000 package. At the time of writing you can download a pre-build binary direcly from Bintray

The addition of those two Jars to your classpath will allow the PDF library to decode JPEG2000-encoded data in PDF files.

The content below is no longer valid, but it remains for posterity

The Solution (2009)

The fix is to install the Java Advanced Imaging API. This is available for Windows, Linux and Solaris - there's licensing and a lot more information at that site and we'd recommend looking around, but as this is a quick and dirty installation guide we'll cut directly to the chase.

For UNIX

  1. Open https://jai-imageio.dev.java.net/binary-builds.html
  2. Download the "tar.gz" file of the latest daily build for your architecture - we recommend the daily releases, as the stable 1.1 release doesn't work with some of the JPEG2000 streams you're likely to find in PDF
  3. Untar the file.
  4. Copy the contents of jai_imageio-1_2-nnn/lib to the $JAVA_HOME/jre/lib/ext folder of your JDK.

Linux typically installs Java in /usr/lib/jvm/version, where version depends on which JDK you installed. Here's what I typed:

unzip jai_imageio-1_2-lib-*.zip
cp -r lib /usr/lib/jvm/java-6-sun/jre

For Windows

  1. Open https://jai-imageio.dev.java.net/binary-builds.html
  2. Download the latest daily release from the 1.2 series and unzip it. You'll have a bin and lib folder - the contents of these have to be copied to the bin and lib folders of your JDK install (typically something like C:\Program Files\Java\jre6.

If you're running the PDF Library in a web server you will need to restart it, but otherwise that's all that's required to add JPEG 2000 support to Java.