Java fade in and out of images
animation, image, java, swing, transparency
Solution
Basically, what this does is use the same alpha value, fading in from 0-1 and then using the same alpha, going from 1-0, allowing the two images to cross fade over each other...
The magic basically, happens in the `paintComponent`, where the image coming in using the `alpha` value and the outgoing image uses `1f - alpha`.
Switching between the two images is actually a the same process, expect the `inImage` is swapped for the `outImage`
The timing is little different. Instead of a straight move from `0-1` using a standard delta (ie `0.01` for example), this uses a time based algorithm.
That is, I use a timer which ticks every 40 milliseconds or so, it then does a calculation based on the amount of time the timer has being running and calculates the `alpha` value accordingly...
This allows you to change the amount of time the animation will take, but also provides a slightly better algorithm that takes into account the passive nature of Swings rendering engine...
import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
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.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FadeImage {
public static void main(String[] args) {
new FadeImage();
}
public FadeImage() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
public static final long RUNNING_TIME = 2000;
private BufferedImage inImage;
private BufferedImage outImage;
private float alpha = 0f;
private long startTime = -1;
public TestPane() {
try {
inImage = ImageIO.read(new File("/path/to/inImage"));
outImage = ImageIO.read(new File("/path/to/outImage"));
} catch (IOException exp) {
exp.printStackTrace();
}
final Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (startTime < 0) {
startTime = System.currentTimeMillis();
} else {
long time = System.currentTimeMillis();
long duration = time - startTime;
if (duration >= RUNNING_TIME) {
startTime = -1;
((Timer) e.getSource()).stop();
alpha = 0f;
} else {
alpha = 1f - ((float) duration / (float) RUNNING_TIME);
}
repaint();
}
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
alpha = 0f;
BufferedImage tmp = inImage;
inImage = outImage;
outImage = tmp;
timer.start();
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(
Math.max(inImage.getWidth(), outImage.getWidth()),
Math.max(inImage.getHeight(), outImage.getHeight()));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
int x = (getWidth() - inImage.getWidth()) / 2;
int y = (getHeight() - inImage.getHeight()) / 2;
g2d.drawImage(inImage, x, y, this);
g2d.setComposite(AlphaComposite.SrcOver.derive(1f - alpha));
x = (getWidth() - outImage.getWidth()) / 2;
y = (getHeight() - outImage.getHeight()) / 2;
g2d.drawImage(outImage, x, y, this);
g2d.dispose();
}
}
}
Problem
I am trying to learn how to fade in and out images into another image or from another image. So, if I have 2 images, and 1 is being displayed at the moment, I want to display another image in the background and fade the first image out into the 2nd image. OR, I want to set the focus on the new image and slowly fade it in over the 1st image, then stop displaying the 1st one. I'm not sure how: to set focus, if even needed. I can fade in if I change the alpha to 0 and increment up and only draw one image, however I cannot get it to fade out either with any variation of this code. (i.e. commenting out one image to draw). Edit: Really, all I'm worried about is being able to have 2 images and make the image currently being displayed slowly disappear into the 2nd image. How that is accomplished doesn't need to be with this. Here is a code sample I'm messing with: ``` import java.awt.AlphaComposite; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; public class FadeIn extends JPanel implements ActionListener { private Image imagem; private Image image2; private Timer timer; private float alpha = 1f; public FadeIn() { imagem = (new ImageIcon(getClass().getResource( "/resources/1stImage.jpg"))).getImage(); image2 = (new ImageIcon(getClass().getResource( "/resources/2ndImage.jpg"))).getImage(); timer = new Timer(20, this); timer.start(); } // here you define alpha 0f to 1f public FadeIn(float alpha) { imagem = (new ImageIcon(getClass().getResource( "/resources/1stImage.jpg"))).getImage(); this.alpha = alpha; } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.drawImage(imagem, 0, 0, 400, 300, null); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); g2d.drawImage(image2, 0, 0, 400, 300, null); } public static void main(String[] args) { JFrame frame = new JFrame("Fade out"); frame.add(new FadeIn()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(420, 330); // frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { alpha += -0.01f; if (alpha <= 0) { alpha = 0; timer.stop(); } repaint(); } } ```