Developer’s Corner: Fast, Pure Java, Open Source PNG Encoder for GeoServer

Dear All,
lately Andrea Aime from GeoSolutions has been working hard in order to create a pure Java PNG encoder that was good enough to replace the native one we have been using so far. You might wonder why we were doing this, well a few reasons:

  1. the standard PNG encoder shipped with the Oracle JDK is very poor in terms or encoding speed which has a bad impact on WMS performance overall
  2. There is no native PNG encoder for Windows 64 bits platforms
  3. Using the native PNG encoder requires an extra installation step as the user needs to install the native libraries
Well, I guess this is enough to start off a new writer/encoder. Here below you can find some excerpts from an email we sent to the GeoServer developers’ mailing list describing the status of the work.
The faster PNG encoder module in community is ready for people to try out: I’ve tested it with a number of demo layers, seems to be working, so I though it was time to try out its performance (get the popcorn and have a seat).
The comparisons involve 3 PNG encoders:
* The JDK one, which it not tunable (it actually ignores our quality/compression indications) and compresses everything to the fullest, delivering consistently the smallest PNG in exchange for a very slow performance. 
* The native ImageIO one, which you can get only if you have properly installed ImageIO, which honors the compression settings by altering the level of effort involved in encoding a PNG image, delivering larger images but also providing better performance. This is the encoder you cannot have on Windows 64 and OSX, since there is no native ImageIO for those platforms
* The new encoder, based on PNGJ, a open source, java based,  low level PNG encoder, coupled with high performance scanline extractors from yours truly, that efficiently feed the image bytes into PNGJ
First I did a very silly test against topp:states, usual style, map size 780×330, using ab (apache bench) with 1 and 4 threads, comparing the throughput and output size for a compression level of 25 (the default one in the WMS panel).
Results:
Threads   JDK      Native ImageIO    PNGJ based
1         11.7     25.4              36.9
4         38.9     75.11             94.5
Size      39KB     55KB              45KB
Well, as you can see the improvement over JDK is _very_ significant, but the one over NativeIO is not to throw away either.
The output size is good news too, the new encoder manages to be faster than the CLib one and yet provides a output size closer to the JDK one (which, as said, uses every possible effort to have the smallest possible output).
Yet, this use case is a toy, the map is small, the vectors are simple.
So I’ve decided to try something bigger, the FOSS4G 2010 benchmark, the vector map of the whole spain with roads, buildings, contour lines, labels.
I’ve collected the full results in this Google Spreadsheet:
Here is just the comparison chart (click to enlarge):

Well, I’d say the speedup is again rather good compared to the plain JDK encoder, and not to throw away compared to the ImageIO native encoder.
Again, I’ve reached for one of the output maps of the benchmark and compared sizes (this is a 904×764 image with a dense set of countour lines, road network, some labels, some polygons):
* JDK -> 338KB
* Native ImageIO -> 509KB
* PNGJ based -> 367KB
Again, close to the JDK size, yet faster than the native ImageIO encoder in speed.
Not too bad, if I may say! (Windows Server users, likely using 64 bits JVMs, should pop the champagne :-p )
I’ve added the module to the nightly build on the master branch, and if you are a developer, you can load it by using the -Ppng profile with your maven commands. If you are a user you can download it from here. As mentioned above the plugin is available only for the master build, but it _should_ still be compatible with 2.4.0.
I’d like to get some feedback from the early testers, and then push this module for extension status in the 2.4.x series to have a larger user base test it.
Important remark for users that might be reading this: before you run downloading the new module, remember that the speedup is solely in the PNG encoding phase.
If your map takes 1 second or more to draw, you probably have troubles in data setup, don’t waste your time trying a difference PNG encoder, optimize your data or styles instead.
If instead your current maps already get returned in less than, say, 0.3 seconds then yes, give the new PNG encoder a try.

Moving on I’ve run the same benchmarks  (last WMS shootout) to see how the new PNG encoder performs under OpenJDK 7 (1.7.0_45), which is known to have a slower rasterizer but better scalability.
Well… have a look, this is the comparison between JDK own PNG encoder, ImageIO native one, and the new pure java PNGJ based encoder (click to enlarge):

See anything? No? Well, let me try to show the comparison between last week JDK 7 results and this week OpenJDK 7 on just the PNGJ based encoder (click to enlarge):

Got the message now? 🙂
Full details here: 
Long story short, at 1 thread OpenJDK 7 is slower, but it matches Oracle JDK already at 2 and gets better quickly as we go up with the number of threads*.
And while even the ImageIO native encoder gets a benefit from using OpenJDK 7 (10-15% faster than with Oracle JDK), the PNGJ based encoder really shines with it… while my previous mail was really good news for Windows 64 bit users, I’m picturing very large smiles on Linux user faces today** 😉
*: This does not mean OpenJDK will be better for any kind of map, the denser the map, the slower OpenJDK 7, since it’s really slower at rasterizing. The maps in the last WMS shootout were not really that dense (the typical OSM map has more elements in it)
**: OpenJDK binary builds are not officially available for Windows, however, for those that dare to try, there are unofficial builds here:
Would be nice to hear from Windows users how these perform (and how stable they are)

So, if you’re eager to try out the new PNG encoder, download it from the nightly builds and drop its contents in geoserver/WEB-INF/lib, restart, and enjoy raster PNG encoding. While the module has been built inside the 2.5.x series, it is also compatible with 2.4.x and 2.3.x.

If you’d like to know more about what you could achieve with GeoServer, do not hesitate and get in touch with usIf you need professional services to get started with Open Source software make sure to have a look at our GeoSolutions Enterprise Services.

The GeoSolutions team.