IDL 6.2 added several new capabilities to the IDLgrImage class in the object graphics system. One of them is the ability to support large images using tiling. (Another is significantly faster rendering time in typical cases.)

mg_tilejp2 demo

The new tiling features allow portions of the image to be read from a data source as needed. For applications that zoom using data sources with an image pyramid, level of detail rendering is used. For example, if a thumbnail of the entire image is needed, only a low resolution image is requested from the data source and rendered by IDLgrImage.

The mechanics of how this works requires a bit of communication between the destination object (IDLgrWindow, IDLgrBuffer, IDLgrClipboard or IDLgrPrinter support it) and the IDLgrImage object using a few new methods (most notably, queryRequiredTiles for the destination objects and setTileDatafor IDLgrImage).

Running the demo

The demo program is a minimal tiling image viewer which supports scrolling (click and drag as well as with the arrow keys) and zooming (page up and page down). To test it out:

  1. First download the source code (mg_tilejp2.pro and mg_tilejp2_demo.pro).
  2. Change directories in IDL to a directory that you want to save the JPEG 2000 data file in.
  3. You need to run MG_TILEJP2_DEMO at least the first time you run the demo code in order for the JPEG2000 image to be created. After that, you can run MG_TILEJP2 directly.

How it works

The basic steps are pretty simple:

  1. set a few properties on the IDLgrImage object when you create it,
  2. query the destination object with the new queryRequiredTiles method for any new tile data to read, and
  3. set the tile data with the new setTileData method of IDLgrImage.

First, there a few new properties of IDLgrImage that you can now set. The TILING keyword must be set and TILED_IMAGE_DIMENSIONS must specify the full size of the image. The IDLgrImage initialization in the demo program looks like:

oimage = obj_new('IDLgrImage', name='image', order=1, $
                 /tiling, $
                 tile_show_boundaries=0, $
                 tile_level_mode=1, $ ; automatic mode for image pyramid
                 tiled_image_dimensions=imageDims, $
                 tile_dimensions=jp2TileDims)

The size of each tile is set through the TILE_DIMENSIONS keyword; the default value is [1024, 1024]. The keyword TILE_SHOW_BOUNDARIES can be set to show the boundaries of the tiles (handy when debugging). Finally, TILE_LEVEL_MODE specifies whether the application specificies the level through the TILE_CURRENT_LEVEL property (0) or if it done automatically (1). Since our demo program has a data source with an image pyramid, we can use automatic.

The guts of the tile handling is in the MG_TILEJP2_REFRESH routine that is called whenever the image needs to be redrawn (usually because the VEWPLANE_RECT of the view has been modified). Our refresh routinen is a typical example of filling in the tile data from a JPEG 2000 file:

pro mg_tilejp2_refresh, pstate
  compile_opt strictarr

  oimage = (*pstate).oview->getByName('model/image')
  reqTiles = (*pstate).owindow->queryRequiredTiles((*pstate).oview, $
                                                   oimage, $
                                                   count=nTiles)

  if (nTiles gt 0) then widget_control, /hourglass

  for t = 0L, nTiles - 1L do begin
    subrect = [reqTiles[t].x, reqTiles[t].y, $
               reqTiles[t].width, reqTiles[t].height]

    level = reqTiles[t].level
    scale = ishft(1, level) ; scale = 2^level
    subrect *= scale

    ojp2 = obj_new('IDLffJPEG2000', (*pstate).jp2filename, $
                   persistent=0)
    tileData = ojp2->getData(region=subrect, $
                             discard_levels=level, $
                             order=1)
    obj_destroy, ojp2
    oimage->setTileData, reqTiles[t], tileData, no_free=0
  endfor
  (*pstate).owindow->draw, (*pstate).oview
  widget_control, hourglass=0
end

Note how nicely the output of IDLgrWindow::queryRequiredTiles meshes with the keywords of IDLffJPEG2000::getData and the parameters of IDLgrImage::setTileData.

The rest is, as they say, details—that is, if you have a basic knowledge of object graphics and widget programming.