I think I’ve just pinpointed the problem, but I’m still not sure what to do about it.
I’ve created various animated gifs using Photoshop and I wanted to display them in my java application. Using ImageIcon, some of them display as they should. Those are the ones with frames that have the same frame rate (such as each frame is 1 second long). However, the gifs that have varying frame rates (ex. one frame is 1 second, the other is .5 seconds, the next is .2) doesn’t seem to be showing correctly. Once the gif reaches the frames that vary in seconds the image messes up. Some examples include the background briefly changing color and half of the image disappearing, or most of the image disappearing with the gif still animating.
I’m having a difficult time articulating, but do I need to use something else other than ImageIcon to correctly load the gif with varying frame rates? Like something with BufferedImage?
Edit: Added complete code below. Again, it works for the image with equal frame rates, but not for one with varying frame rates.
here is the image that works fine
and here is the image that messes up
import java.awt.*;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
public class Creature extends JWindow {
public void initCreature() {
JPanel contentPane = (JPanel) getContentPane();
ImageIcon idleImage = new ImageIcon(getClass().getResource("img.gif"));
// Set window properties
getRootPane().putClientProperty("Window.shadow", false);
setBackground(new Color(0,0,0,0));
setAlwaysOnTop(true);
contentPane.setOpaque(false);
// Get size of user's screen
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
Rectangle screen = defaultScreen.getDefaultConfiguration().getBounds();
int taskbarheight = (int) (Toolkit.getDefaultToolkit().getScreenSize().height
- GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds().getHeight());
int x = (int) screen.getMaxX() - idleImage.getIconWidth();
int y = (int) screen.getMaxY() - idleImage.getIconHeight() - taskbarheight;
JLabel imageLabel = new JLabel(idleImage);
setSize(idleImage.getIconWidth(), idleImage.getIconHeight());
contentPane.add(imageLabel);
setLocation(x, y);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
Creature cr = new Creature();
cr.initCreature();
}
});
}
}
2
Answers
The
imageLabel
doesn’t know to repaint when the GIF’s frame changes. You need to tell the ImageIcon to notify the JLabel of frame changes, by passing the JLabel to setImageObserver:From that method’s documentation:
The frame rates seem the same in both versions (one seen in a browser, the other in a
JLabel
). The actual problem is that the rendering in Java becomes ‘clipped’ in the areas of the animation that do not change.At a guess I’d say the problem is that PhotoShop is using an advanced encoding to ensure that only the parts of the frame that change, are updated. Note that although Java supports a particular file type like GIF, PNG or JPEG, does not mean it correctly understands every encoding type for each file type.
A simpler image that, for every change, changes the entire frame should work better, but also be larger in bytes. In fact, you can see that working in the other image. Because the little dragon is hunching down then rising back up, all parts of the visible image need to change, so the animation of that cannot be optimized in the same way as the first image can.