If you are having an issue with graphics performance make sure you try compatible images before trying anything else since it is so easy to introduce.
Before deploying to site I was worried that the speed up I was seeing was in some way down to my dev machine working well with compatible images so I wrote the tool below to test if the improvement was the same which it was. Some notes:
- The tool requires an image. When I attempted to create an in-memory image there was no difference in run times.
- Results are printed on the command line so remember to use java.exe and not javaw.exe
- I went to some effort so that this program was a single class to make it easy for the support guys to run. I don't usually like to implement Runnable on a class that isn't just a Runnable.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Color; | |
import java.awt.Graphics; | |
import java.awt.GraphicsConfiguration; | |
import java.awt.GraphicsDevice; | |
import java.awt.GraphicsEnvironment; | |
import java.awt.Image; | |
import java.awt.Transparency; | |
import java.awt.image.BufferedImage; | |
import java.io.File; | |
import java.io.IOException; | |
import javax.imageio.ImageIO; | |
import javax.swing.JFrame; | |
import javax.swing.JPanel; | |
import javax.swing.SwingUtilities; | |
public class CompatibleImageBenchMark extends JPanel implements Runnable | |
{ | |
public static void main(String[] args) | |
{ | |
SwingUtilities.invokeLater(new CompatibleImageBenchMark()); | |
} | |
Image optimal, suboptimal; | |
public void run() | |
{ | |
try | |
{ | |
optimal = createCompatibeImage(); | |
suboptimal = createSuboptimalImage(); | |
} | |
catch (Exception e) | |
{ | |
e.printStackTrace(); | |
} | |
JFrame frame; | |
frame = new JFrame("Compatible image benchmark"); | |
frame.setSize(800, 600); | |
frame.setContentPane(this); | |
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
frame.setVisible(true); | |
} | |
@Override | |
protected void paintComponent(Graphics g) | |
{ | |
super.paintComponent(g); | |
long start, elapsed; | |
start = System.currentTimeMillis(); | |
for (int i = 0; i < 10; i++) | |
{ | |
g.drawImage(suboptimal, 10, 10, null); | |
} | |
elapsed = System.currentTimeMillis() - start; | |
System.out.println("elapsed for suboptimal image is " + elapsed + "ms"); | |
start = System.currentTimeMillis(); | |
for (int i = 0; i < 10; i++) | |
{ | |
g.drawImage(optimal, 10, 10, null); | |
} | |
elapsed = System.currentTimeMillis() - start; | |
System.out.println("elapsed for optimal image is " + elapsed + "ms"); | |
} | |
private BufferedImage createCompatibeImage() throws IOException | |
{ | |
BufferedImage suboptimalImage = createSuboptimalImage(Color.GREEN); | |
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); | |
GraphicsDevice gs = ge.getDefaultScreenDevice(); | |
GraphicsConfiguration gc = gs.getDefaultConfiguration(); | |
// Create an image that does not support transparency | |
BufferedImage image = gc.createCompatibleImage( | |
suboptimalImage.getWidth(), suboptimalImage.getHeight(), Transparency.TRANSLUCENT | |
); | |
Graphics g; | |
g = image.getGraphics(); | |
g.drawImage(suboptimalImage, 0, 0, null); | |
return image; | |
} | |
private BufferedImage createSuboptimalImage() throws IOException | |
{ | |
BufferedImage suboptimalImage = ImageIO.read(new File("my image.png")); | |
return suboptimalImage; | |
} | |
} |