How can I improve the speed of my tile grabbing class?
I'm working on a Java project that involves retrieving a large amount of images for use as icons. Previously, I had a folder containing a large amount of individual .png files - this worked fairly well, but took up a lot of space and was fairly difficult to deal with. Instead, I tried to write a class that would allow me to extract a scaled tile in an ImageIcon format from one larger file.
It took a while, but I managed to make it work using a PixelGrabber and the BufferedImage.setRGB() method, using references that I found here on Stack Overflow. You can see the class below (it's likely that it could use some improvement in places):
/**
* Java tile grabbing class: Create ImageIcons from coordinates out of an image
*
* @author Protractor Ninja
* @version 1.00 2011/2/21
*/
import javax.swing.ImageIcon;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.awt.image.ImageObserver;
import java.awt.Image;
import java.io.File;
import java.lang.Exception;
import javax.swing.*;
import java.awt.image.WritableRaster;
import java.util.*;
public class TileGrabber {
private BufferedImage image;
private File imageFile;
private PixelGrabber grabber;
private int tileWidth;
private int tileHeight;
private int[] pixels;
/*
* Creates a tile grabber object using a filepath and tile heights.
* Tiles should start at zero pixels.
*/
public TileGrabber(String path, int tWidth, int tHeight) {
try {
image = ImageIO.read(this.getClass().getResourceAsStream("/" + path.replaceAll("^/", "")));
pixels = new int[tWidth*tHeight];
tileWidth = tWidth;
tileHeight = tHeight;
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Same as before, but uses an already-created BufferedImage file.
*/
public TileGrabber(BufferedImage img, int tWidth, int tHeight) {
try {
image = img;
pixels = new int[tWidth*tHeight];
tileWidth = tWidth;
tileHeight = tHeight;
} catch (Exception e) {
e.printStackTrace();
}
}
public void setImagePath(String path) {
try {
image = ImageIO.read(this.getClass().getResourceAsStream("/" + path.replaceAll("^/", "")));
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Creates an ImageIcon object from tile coordinates on an image.
*/
public ImageIcon grabTile(int x, int y, int scale) {
x = x*tileWidth;
y = y*tileHeight;
grabber = new PixelGrabber(image, x, y, tileWidth, tileHeight, pixels, 0, tileWidth);
开发者_运维问答 try {
grabber.grabPixels();
} catch (Exception e) {
e.printStackTrace();
}
Image i = getImageFromArray(pixels, tileWidth, tileHeight).getScaledInstance(tileWidth*scale, tileHeight*scale, Image.SCALE_FAST);
return new ImageIcon(i);
}
/*
* Creates an Image from an array of pixels and specified heights.
* Retrieved and modified from a stackoverflow.com question
*/
public Image getImageFromArray(int[] pixels, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
image.setRGB(0,0,width,height,pixels,0, width);
return image;
}
/**
* For testing purposes.
*/
public static void main(String[] args) {
JFrame window = new JFrame("Hello, this is a test");
window.setBounds(0,0,550,500);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TileGrabber grabber = new TileGrabber("terrain.png", 16, 16);
JLabel label = new JLabel(grabber.grabTile(12,8,5));
window.getContentPane().add(label);
window.setVisible(true);
}
}
The only problem is, the primary delay during startup is the delay that happens when all of the icons are being loaded, and I'm not really sure how to make it faster - I'd really like to make it so that the user won't have to wait very long for the program to start.
Is there any way I could improve the code I have, or, is there an alternate, faster method of doing what I'm attempting to do?
Many thanks for your time.
Have you run the code through a profiler to try and pinpoint the source of the slowness? Not an immediately helpful answer I know but trying to track performance issues without profiling can waste an awful lot of time.
An alternative mechanism that might help would be to delay getting the images until they are needed, obviously this won't help if you need all images from program startup.
As you already have a BufferedImage
, you might see if getSubimage()
is any faster.
Addendum: Here's an example that might let you test with your existing composite.
精彩评论