MrSID is a nifty raster library suffering from the unfortunate constraint of being a C library. Since uDig is supposed to be the best thing around for integration work we will use MrSID as an example of how to get the job done.
MRSID
Check the License
The MrSID license is pretty sweet; it lets you both develop with the library (on a reasonable number of machines) and redistribute the result:
You will need to keep this license file for later; we will be including it in our "MrSID" plugin.
Download the Binaries
Head on over to LizardTech (sign up as needed) and grab a download:
http://www.lizardtech.com/developer/members/downloads.php
The binaries are available for a range of platforms; my impression is we make a single:
- com.lizardtech.dsdk plugin
With the binaries held as a platform specific fragments:
- com.lizardtech.dsdk-win32 fragment
Create JNDI Wrappers
This is the annoying part; MrSID like many C++/C libraries has not supplied java bindings. Searching around on the web there are a couple half hearted attempts mostly concerning unsupported SWIG based bindings of GDAL.
One solutions would be to generate the bindings by hand (fun fun), or we can start to look at tools. Since we have had recent plesent experience with JOGL we may as well check out the tool they use to produce OpenGL bindings:
So far this is looking pretty good on the tech side; and horrible on the documentation side.
After a battle with the above tool it appears that it would take at least a week to get it to spit out decent bindings.
GDAL
Another C project that wraps up MrSID (and ECWSDK) is the GDAL project. Searching around the web I can find a couple of examples of GDAL bindings being available:
gvSIG
The gvSIG project has some GDAL bindings (only evidence is a GeoServer discussion on the topic). Since the project is GPL I am going to give this one a miss - we can reach a larger audience by staying with LGPL.
imageio-ext
The ImageIO project has some GDAL goodness as a result of a Google Summer of Code project.
While you can use ImageIO stuff directly, it is usually used in collaboration with JAI. The benef of using JAI is a declarative style of image processing similar to SQL. You define a chain of operations and "pull" data through from disk. Because it is declarative (you only say what you want) the ImageIO library can do tricks and optimizations for you - such as working with a tile cache.
To use ImageIO to work with rasters it is way more fun to go through the GeoTools project. It serves up a nice GridCoverage abstraction that slots into the existing SLD based rendering. The consulting company GeoSolutions and the easy thing to do is to hire them.
While we wait for that to happen let's grab the GDAL bindings they made and try them out:
To build this thing you need to have JAVA_HOME set and then:
mvn install -Ddeploylibs=true -Pfullkakadu -Dmaven.test.skip=true
This will deploy some DLL files into your JRE and build as much stuff as possible.
DLL HELL
Their are various ways to try to get the java Jars and their native DLL files working together. In the normal course of things the JAR needs to be on the classpath and the DLL needs to be on the library path.
And then we started using OSGi and classloaders.
Root of the Plugin? Not really.
While the jar will be able to find these DLLs, this only works for one level. We can find the GDAL DLL, but the gdal plugins (ie other DLL files) will not be found by GDAL.
Root of a fragment? No
We are supposed to contribute platform specific stuff using fragments. This did not work at all.
- Root of a fragment with jars in the fragments as well? Maybe
This is untested; but since it is the way SWT operates it may actually work out...
JRE/ext/i386? No
This should of worked .. but did not
JRE/bin? YES
JRE Extensions
So at the end of the day do the following:
If you do not do this your applications will start up just using the java "boot classpath", and none of the JRE extensions will be picked up.
UDIG Integration
The first task is to simply list these resources in the uDig catalog; to accomplish that we need to implement a couple of extension points provided by the uDig "GIS Platform".
To try this stuff out:
You can then import these plugins into your workspace:
- net.refractions.udig.catalog.imageio - the actual plugin
- net.refractions.udig.catalog.imageio.win32.x86 - fragment used to experiment with DLL hell
net.refractions.udig.catalog.ui.fileFormat
The File Open Dialog needs to know what kind of files the application supports; it does so by processing this fileFormat extension point.
<extension
point="net.refractions.udig.catalog.ui.fileFormat">
<fileService
fileExtension="*.ecw"
name="%ECW"/>
<fileService
fileExtension="*.jp2"
name="%JP2"/>
</extension>
The above example adds the ECW and JP2 files to the list.
The strange "%" syntax means the value name is translatable. We need to supply the (possibly locale specific) name in a plugin.properties file:
net.refractions.udig.catalog.ServiceExtention
Next up we need to teach the uDig catalog (ie the catalogue data structure) about our new format type.
<extension point="net.refractions.udig.catalog.ServiceExtension">
<service
class="net.refractions.udig.catalog.imageio.internal.ImageServiceExtension"
id="imageio"
name="%ImageIO"/>
</extension>
ImageIO=Image IO Extensions
This extension point points out a class, ie ImageServiceExtention, which will act as a factory. This class is an implementation of ServiceExtention2 and will be used to answer a few questions about our new format(s):
- createParams(url): create "sensible" connection parameters given only a URL
- createService( id, params ): create a IService (representing the file in the catalog)
- reasonForFailure( params): human readable description of why we could not connect
- reasonForFailure( url ): ditto
Implementing IService
IService is covered in a bit more detail in the GIS Platform documentation, but if you wander into uDig you may find the code full of all sorts of interesting hacks (nested classes to save a few pointers and so on).
Here is a picture:

And you can check out the code here:
We started this code by copying an example (WorldImageService), and broke it down into a few files for readability.
IService has the job of representing the file on disk, and reporting back connection information (such as the file not being readable, or the file being missing).
IServiceInfo is a description of the file. This information may come from the operating system, or from the file header as needed.
Implementing IGeoResource
IGeoResource represents the actual contents of the file. If the file has more than one kind of content (it does happen!) then there will be a GeoResource for each kind of content.

The workflow for IGeoResource is to resolve to any API you can image. In this case we are interested in turning ourselves into a GridCoverageReader. We could also resolve directly to the GDAL Dataset API as well.
The final part of the puzzle is IGeoResourceInfo which is the all important description of the content. Particular important is the projection and bounds of the content. This information pretty much always has to come from the file header (or metadata).
GridCoverage source = (GridCoverage) resource.findResource();
org.opengis.geometry.Envelope ptBounds = source
.getEnvelope();
env = new Envelope(ptBounds.getMinimum(0), ptBounds
.getMaximum(0), ptBounds.getMinimum(1), ptBounds
.getMaximum(1));
CoordinateReferenceSystem geomcrs = source
.getCoordinateReferenceSystem();
If you are ever stuck looking at all the data and calculating the bounds yourself be sure to cache the answer ... and ask yourself if you really are working with a good spatial format?
GeoTools Integration (Optional)
The GeoTools project is responsible for the GridCoverage and GridReader ideas provided above. This work seems to be happening in a private svn ... a few questions later and it is commited as an unsupported modules on both 2.4.x and trunk.