My game allows scrolling of large maps. Because the entire map doesnt fit into memory, I have broken the map into smaller tiles, as the user scrolls the map, the tiles are loaded into memory (I do some fancy stuff to pre load tiles the user may scroll to next, and I keep previously loaded tiles in memory with a soft reference in case they are re used).
When I load a tile, I convert the tile to a BufferImage that is compatable with the screen. The process is,
- Load the .png file with ImageIO to a BufferedImage
- create a new bufferedImage, and copy the tile from 1) to the new image
- cache the image from 2)
- draw the cached image to the screen when needed
Steps 1,2 and 4 are very fast. Step 1 takes about 7ms, and step 4 takes about 1ms (256x256 png images).
Step 3 takes about 30ms, using the code below,
URL imageLocation = ...
BufferedImage fromFile = ImageIO.read(imageLocation);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics g = image.getGraphics();
g.drawImage(fromFile, 0,0, null);
g.dispose();
It seems very odd that it takes longer to transform the image in memory than it does to read it compressed from disk.
My question is, can I read the file from memory into a BufferedImage of arbitrary Type, skipping the intermediate step?
I tried using ImageReadParam and setDestination, with the code below (stolen from code in ImageIO),
InputStream istream = null;
try {
istream = input.openStream();
} catch (IOException e) {
throw new IIOException("Can't get input stream from URL!", e);
}
ImageInputStream stream = ImageIO.createImageInputStream(istream);
Iterator iter = ImageIO.getImageReaders(stream);
if (!iter.hasNext()) {
return null;
}
ImageReader reader = (ImageReader)iter.next();
ImageReadParam param = new ImageReadParam();
BufferedImage destination = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
param.setDestination(destination);
reader.setInput(stream, true, true);
BufferedImage bi = reader.read(0, param);
stream.close();
reader.dispose();
return bi;
But this throws,
Exception in thread “Map panel background drawer” java.lang.IllegalArgumentException: ImageReadParam num source & dest bands differ!
at javax.imageio.ImageReader.checkReadParamBandSettings(ImageReader.java:2746)
at com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1357)
at com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1530)
at games.strategy.triplea.image.TileImageFactory.createImageDirectly(TileImageFactory.java:243)
at games.strategy.triplea.image.TileImageFactory.startLoadingImage(TileImageFactory.java:179)
at games.strategy.triplea.image.TileImageFactory.getImage(TileImageFactory.java:141)
at games.strategy.triplea.image.TileImageFactory.getBaseTile(TileImageFactory.java:110)
at games.strategy.triplea.ui.screen.BaseMapDrawable.getImage(IDrawable.java:307)
at games.strategy.triplea.ui.screen.MapTileDrawable.draw(IDrawable.java:238)
at games.strategy.triplea.ui.screen.Tile.draw(Tile.java:126)
at games.strategy.triplea.ui.screen.Tile.getImage(Tile.java:88)
at games.strategy.triplea.ui.BackgroundDrawer.run(MapPanel.java:853)
at java.lang.Thread.run(Thread.java:595)
Thanks for any help.