3

I have a couple of huge images which can't be loaded into the memory in whole. I know that the images are tiled and all the methods in the class ImageReader give me plausible non zero return values for

getTileGridXOffset(int), getTileGridYOffset(int), getTileWidth(int) and getTileHeight(int).

My problem now is that I want to read one tile only to avoid having to load the entire image into memory using the ImageReader.readtTile(int, int, int) method. But how do I determine what the valid values for the tile coordinates are?

There is the method getNumXTiles() and getNumYTiles() in the interface RenderedImage but all attempts to create a rendered image from the source results into a out of memory/java heap space error.

The tile coordinates can theoretically be anything and I tried readtTile(0, -1, -1) which also works for a few images I tested.

I also tried to reach the metadata for those images but I didn't find any useful information regarding the image layout.

Is there anyone who can tell me how to get the values for the tile coordinates without having to read the entire image into memory? Is there another way which does not require an instance of ImageLayout?

Thank you very much for your assistance.

Harald K
  • 26,314
  • 7
  • 65
  • 111

1 Answers1

0

First of all, you should check that the ImageReader in question supports tiling for the given image, using the isImageTiled(imageIndex). If it doesn't, you can't expect useful values from the other methods.

Then if it does, all tiles for a given image must be equal in size (but the last tile in each column/the last row may be truncated). This is also the case for all tiled file formats that I know of (ie. TIFF). So, using this knowledge, the number of tiles in both dimensions can be calculated:

// Calculate number of x tiles/y tiles:
int cols = (int) Math.ceil(reader.getWidth(imageIndex) / (double) reader.getTileWidth(imageIndex));
int rows = (int) Math.ceil(reader.getHeight(imageIndex) / (double) reader.getTileHeight(imageIndex));

You can then, loop over the tile indexes (the first tile is always 0,0):

for (int row = 0; row < rows; row++) {
    for (int col = 0; col < cols; col++) {
        BufferedImage tile = reader.readTile(imageIndex, col, row);

        // ...do more processing...
    }
}

Or, if you only want to get a single tile, you obviously don't need the double for loops. :-)


Note: For ImageReaders/images that don't support tiling, the getTileWidth and getTileHeight methods will just return the same as getWidthand getHeight, respectively.

Also, the readTile API docs says:

If the arguments are out of range, an IllegalArgumentException is thrown. If the image is not tiled, the values 0, 0 will return the entire image; any other values will cause an IllegalArgumentException to be thrown.

This means your example, readtTile(0, -1, -1) should always throw an IllegalArgumentException regardless of the tiling... I suspect some implementations may disregard the tile coordinates completely, and give you the entire image anyway.


PS: The RenderedImage interface could in theory help you. But it would require a special implementation in the ImageReader. In most cases you will just get a normal BufferedImage (which implements RenderedImage), and is a single (1x1) tile.

Harald K
  • 26,314
  • 7
  • 65
  • 111