Java: Superimpose/overlay animated gif on other animated gif

5.3k views Asked by At

I'm making a small game. It's not an action one, but a puzzle one, so performance is not quite as important. Now, I have the main game area, a background image. In certain occasions, I want to draw other images over parts of the background image. My problem is that both the background image as well as the superimposed one(s) can be animated gifs, with an unknown number of frames (basically, user selected).

Now, what I want to do is basically: Draw the background image and have it animated (if it's a gif), then draw 0-n smaller animated gifs on top of it, position relative to background image, given in pixel coordinates. Additionally, it should be resizeable so that the images zoom/move accordingly.

How end result could look like: https://i.stack.imgur.com/PxdDt.png (just imagine it animated)

I have found a solution to it which works by setting the layout manager to null and using absolutely positioned JLabels with Icons to have them animated, using one as background and the other one added to it as foreground:

background.setSize(backgroundIcon.getIconWidth(), backgroundIcon.getIconHeight());
foreground.setSize(foregroundIcon.getIconWidth(), foregroundIcon.getIconHeight());
background.setLocation(0, 0);
foreground.setLocation(30, 30);
background.setLayout(null);
background.add(foreground);
frame.setLayout(null);
frame.add(background);

(full code below)

Setting the layout manager to null is, as I heard, problematic (esp. since I'd want to add some text to the image later on, though I'd use another Label inside the background one, not the background label itself or something), and resizing seems not to be possible this way as I can't resize the JLabels image icon (found some solutions which splitted the gif into one bufferedImage per layer and resized them all before putting them back together again, through which it loses specific delays between frames and so on). Also, since the position should be pixel perfect, resizing even if possible could be problematic due to rounding errors.

Now, is there a better way to do this? Can I somehow load animated gifs and merge them manually (even tough they may have a different number of layers) so I had to paint only one image? Is there a layout manager where I can set the components positions manually but which automatically scales it if you resize the window/panel? Is there maybe a third-party graphics project that could do what I want off the bat?

Ideally would be something like what I would do if they weren't animations, like building a merged Image and then resizing and displaying that one.

Full code:

import java.awt.Dimension;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public final class Tester  extends JFrame {
    public static void main(String[] args) throws MalformedURLException {
        new Tester();
    }

    private Tester() throws MalformedURLException {
        setTitle("Tester");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Icon backgroundIcon = new ImageIcon(new URL("http://s5.favim.com/orig/51/animated-gif-gif-hands-sign-language-Favim.com-542945.gif"));
        Icon foregroundIcon = new ImageIcon(new URL("http://i.imgur.com/89HANHg.gif"));

        JLabel background = new JLabel(backgroundIcon);
        JLabel foreground = new JLabel(foregroundIcon);

        // ugly
        background.setSize(backgroundIcon.getIconWidth(), backgroundIcon.getIconHeight());
        foreground.setSize(foregroundIcon.getIconWidth(), foregroundIcon.getIconHeight());
        background.setLocation(0, 0);
        foreground.setLocation(30, 30);
        background.setLayout(null);
        background.add(foreground);
        setLayout(null);
        add(background);

        // set size of frame to size of content
        setResizable(false);
        getContentPane().setPreferredSize(new Dimension(backgroundIcon.getIconWidth(), backgroundIcon.getIconHeight()));
        pack();

        setLocationRelativeTo(null);
        setVisible(true);
    }
}
1

There are 1 answers

11
Andrew Thompson On BEST ANSWER

This works for me. The smaller orbital image is centered inside the larger moon phases image.

import java.awt.*;
import javax.swing.*;
import java.net.*;

public final class Tester  extends JFrame {
    public static void main(String[] args) throws MalformedURLException {
        new Tester();
    }

    private Tester() throws MalformedURLException {
        setTitle("Tester");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Icon backgroundIcon = new ImageIcon(
                new URL("http://1point1c.org/gif/moon/moonphases.gif"));
        Icon foregroundIcon = new ImageIcon(
                new URL("http://1point1c.org/gif/thum/plnttm.gif"));

        JLabel background = new JLabel(backgroundIcon);
        JLabel foreground = new JLabel(foregroundIcon);

        background.setLayout(new GridBagLayout());
        background.add(foreground);
        add(background);

        pack();

        setLocationByPlatform(true);
        setVisible(true);
    }
}