6
\$\begingroup\$

In a jPanel, I'm displaying a 1203x1203 background that I rotate every 30ms. Problem is, Swing is known to be a slow library, and I assume rotating a huge picture at a quick rate would be quite resources demanding. But I've a powerful PC, and even if on mine it runs fine, I wonder if on slower machines it will be as fluid.

public static BufferedImage createRotatedCopy(BufferedImage img, double rotation) {
    int w = img.getWidth();
    int h = img.getHeight();
    BufferedImage rot = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    double theta = 2 * Math.PI * rotation;
    AffineTransform xform = new AffineTransform();

    xform.translate(0.5 * h, 0.5 * w);
    xform.rotate(theta);
    xform.translate(-0.5 * w, -0.5 * h);
    Graphics2D g = (Graphics2D) rot.createGraphics();
    g.drawImage(img, xform, null);
    g.dispose();
    return rot;
}

I wonder first if there is any way to optimize it. What I can do, is to use a smaller picture, apply the rotation and resize it. But I don't know if it would be more efficient.

And the rotation callback is:

    exec = Executors.newSingleThreadScheduledExecutor();
    exec.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            bgAngle += 0.001;
            bgAngle = (bgAngle >= 1) ? 0 : bgAngle;
            rotBg = Menu.createRotatedCopy(toBufferedImage(bg.getImage()), 
                    bgAngle);
            repaint();
        }
    }, 0, 30, TimeUnit.MILLISECONDS);

Do you see anything that could be optimized? Or outright another way to do what I want?

\$\endgroup\$
1
\$\begingroup\$

Here is something you could do which would work for computers not fast enough to rotate the image every 30 ms. Instead of requesting a repaint every 30ms, define the angularVelocity (rads / second) and call a repaint every 30 ms or as fast as possible, if it can't make 30 ms. Then compute angleRad = angularVelocity * (System.currentTimeMillis() - startTime).

Swing efficiency is not the problem. The image manipulation library is the bottleneck. I don't think you can do anything to make it faster. There are probably some (non-Java) libraries that can rotate images much faster using the GPU, but mixing those with Java would make the installation a nightmare.

Another solution would be to store all rotated images in memory. That might work if you were rotating the image by 90 degrees increments, but you would need an awful lot of RAM for all images incremented by 0.001 rads.

As an aside, I believe repaint() now has to be called on the Swing event thread, which was not the case before Java 7. I'm not quite sure and I could not find about this on the web, so I would be grateful if someone could comment. You could use a SwingWorker if that is the case. Actually, for cleanness, you should probably stick to a SwingWorker. It does exactly want you are doing, and is made especially for that.

\$\endgroup\$
  • \$\begingroup\$ From the tutorial, they say that only Swing methods which are labeled "thread safe" in the API are thread safe. repaint() is not labelled thread-safe... but is an awt method. \$\endgroup\$ – toto2 Jun 29 '14 at 15:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.