I've been trying to visually simulate a traffic problem, but for some reason I get only blank output in my swing window. Instead of a constantly-moving picture with vehicles, I get only a grey screen.
My drawing class looks as follows:
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class RoadNetwork extends JPanel {
BufferedImage tempicon = ImageIO.read(getClass().getResource("Truck.png"));
BufferedImage truckicon = new BufferedImage(tempicon.getWidth(), tempicon.getHeight(), BufferedImage.TYPE_INT_ARGB);
public RoadNetwork() throws IOException {
repaint();
}
protected void paintComponent (Graphics g) {
super.paintComponent(g);
g.clearRect(0, 0, 600, 600); // insert window size parameters here
for (int i = 0; i < AMEC.vehiclecounter; i++) {
if (AMEC.vehicle[i].spawned == true && AMEC.vehicle[i].finished == false) { // if the truck is somewhere on the plant
g.drawImage(truckicon, AMEC.getcoord(i)[0], AMEC.getcoord(i)[1], this);
}
}
g.drawImage(truckicon, 100, 100, this);
}
}
The call to the class in my main function is done as follows:
RoadNetwork roadnetwork = new RoadNetwork();
roadnetwork.setVisible(true);
JFrame frame = new JFrame();
frame.add(roadnetwork);
frame.setSize(600, 600);
frame.setVisible(true);
Then, with every iteration of my simulation, I call
roadnetwork.repaint();
What am I missing?
BufferedImage tempicon = ImageIO.read(getClass().getResource("Truck.png"));
BufferedImage truckicon = new BufferedImage(tempicon.getWidth(), tempicon.getHeight(), BufferedImage.TYPE_INT_ARGB);
At the end of the 2nd code line, truckicon is still completely invisible (since it is a transparent image that we have drawn nothing to). Try instead.
BufferedImage truckicon = ImageIO.read(getClass().getResource("Truck.png"));
I hate not knowing why something works. But I remember going through the Graphics totorial and seeing them do this in the constructor where they seem to draw the second image
BufferedImage img = ImageIO.read(imageSrc);
int w = img.getWidth(null);
int h = img.getHeight(null);
BufferedImage bi = new
BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
g.drawImage(img, 0, 0, null);
Here's the fix I made. I wish I could give more explanation, but feel free to check out the tutorial I linked
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RoadNetwork extends JPanel {
BufferedImage tempicon;
BufferedImage truckicon;
public RoadNetwork() throws IOException {
tempicon = ImageIO.read(getClass().getResource("resources/stack_reverse.png"));
int w = tempicon.getWidth(null);
int h = tempicon.getHeight(null);
truckicon = new
BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = truckicon.getGraphics();
g.drawImage(tempicon, 0, 0, null);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//g.clearRect(0, 0, 600, 600); // insert window size parameters here
// for (int i = 0; i < AMEC.vehiclecounter; i++) {
// if (AMEC.vehicle[i].spawned == true && AMEC.vehicle[i].finished ==
// false) { // if the truck is somewhere on the plant
// g.drawImage(truckicon, AMEC.getcoord(i)[0], AMEC.getcoord(i)[1],
// this);
// }
// }
g.drawImage(truckicon, 100, 100, this);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
try {
RoadNetwork roadnetwork = new RoadNetwork();
roadnetwork.setVisible(true);
JFrame frame = new JFrame();
frame.add(roadnetwork);
frame.setSize(600, 600);
frame.setVisible(true);
} catch (IOException es) {
es.printStackTrace();
}
}
});
}
}
Also, I was going to suggest #AndrewThompson's answer, but because I didn't know the reason you were using two BufferedImages, I didn't want to suggest it. You may have been trying to do what the tutorial was doing.
Related
I'm trying to make my own, very inefficient "image copier". I'm doing it by reading the pixels from the original image on to an array and then resetting those same pixels in my default BufferedImage. And then repaint the frame. Row by row.
I'm trying to repaint the frame every after each row of pixels has been stored in the array. But the frame only gets updated once; when it finishes storing the pixels.
My code is all over the place, and I'm probably doing a lot of stuff wrong. This is for an assignment and I've been going at it for a while now and would really appreciate some help.
Here is my code:
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.*;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class pixelReloc extends JComponent {
static BufferedImage image,newImg;
static JFrame frame;
public void initialize() {
int width = getSize().width;
int height = getSize().height;
int pixels[];
int index = 0;
int j=0,i=0;
File f = new File("/path/to/file/images/shrek4life.jpg");
try{
image = ImageIO.read(f);
}catch(IOException e){}
System.out.println("checkpoint 1");
image = createResizedCopy(image,500,500,true);
newImg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
pixels = new int[(image.getWidth()) * (image.getHeight())];
System.out.println("checkpoint 2");
for(i= 0; i < newImg.getWidth(); i++){
for(j = 0; j < newImg.getHeight(); j++){
//get the rgb color of the old image
Color c = new Color(image.getRGB(i, j));
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
pixels[index++] = (r<<16) | (g<<8) | b;
}
newImg.setRGB(0, 0, i, j, pixels, 0, 0);
frame.getContentPane().validate();
frame.getContentPane().repaint();
}
System.out.println("checkpoint 4");
//image.setRGB(0, 0, width, height, data, 0, width);
}
public BufferedImage createResizedCopy(BufferedImage originalImage,
int scaledWidth, int scaledHeight,
boolean preserveAlpha)
{
System.out.println("resizing...");
int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
Graphics2D g = scaledBI.createGraphics();
if (preserveAlpha) {
g.setComposite(AlphaComposite.Src);
}
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();
return scaledBI;
}
public void paint(Graphics g) {
if (image == null)
initialize();
g.drawImage(newImg, 0, 0, this);
}
public static void main(String[] args) {
frame = new JFrame("P I X E L S");
frame.getContentPane().add(new pixelReloc ());
frame.setSize(500, 500);
frame.setLocation(100, 100);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.setVisible(true);
}
}
Here is the picture I'm reading the pixels from:
and this is how it's coming out:
The program doesn't give any errors or anything.
The basic answer to your question is, you're blocking the Event Dispatching Thread.
Swing is both single threaded and NOT thread safe. This means you can't run long running or blocking operations from within the EDT AND you should't not update the UI or some state the UI depends on from outside the EDT.
I recommend that you start by having a look at Concurrency in Swing.
This leaves with three basic options:
Use another Thread. This is problematic as you need to ensure that any state that the UI relies on is only updated from within the context of the EDT
Use a SwingWorker. This is basically the previous option, but with built in management which allows you to publish updates which are process'ed on the EDT
Use a Swing Timer. In your case, this is probably not the best solution, but it is the simplest.
For example
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
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 PixelReloc());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Pixel {
private int x, y;
private int color;
public Pixel(int x, int y, int color) {
this.x = x;
this.y = y;
this.color = color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getColor() {
return color;
}
}
public class PixelReloc extends JComponent {
private BufferedImage image;
private BufferedImage newImg;
public PixelReloc() {
SwingWorker<Integer[], List<Pixel>> worker = new SwingWorker<Integer[], List<Pixel>>() {
Integer pixels[];
#Override
protected Integer[] doInBackground() throws Exception {
pixels = new Integer[image.getWidth() * image.getHeight()];
int index = 0;
List<Pixel> pixies = new ArrayList<>(image.getWidth());
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int color = image.getRGB(x, y);
pixels[index++] = color;
pixies.add(new Pixel(x, y, color));
}
publish(new ArrayList<Pixel>(pixies));
pixies = new ArrayList<>(image.getWidth());
Thread.sleep(100);
}
return pixels;
}
#Override
protected void process(List<List<Pixel>> chunks) {
for (List<Pixel> pixels : chunks) {
for (Pixel pixel : pixels) {
newImg.setRGB(pixel.getX(), pixel.getY(), pixel.getColor());
}
}
repaint();
}
};
File f = new File("/Volumes/Big Fat Extension/Dropbox/MegaTokyo/chaotic_megatokyo_by_fredrin-d9k84so.jpg");
try {
image = ImageIO.read(f);
} catch (IOException e) {
}
System.out.println("checkpoint 1");
image = createResizedCopy(image, 200, 200, true);
newImg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
worker.execute();
// pixels = new int[(image.getWidth()) * (image.getHeight())];
// System.out.println("checkpoint 2");
// for (i = 0; i < newImg.getWidth(); i++) {
// for (j = 0; j < newImg.getHeight(); j++) {
// //get the rgb color of the old image
// Color c = new Color(image.getRGB(i, j));
// int r = c.getRed();
// int g = c.getGreen();
// int b = c.getBlue();
// pixels[index++] = (r << 16) | (g << 8) | b;
// }
// }
// System.out.println("checkpoint 4");
//image.setRGB(0, 0, width, height, data, 0, width);
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200) : new Dimension(image.getWidth(), image.getHeight());
}
public BufferedImage createResizedCopy(BufferedImage originalImage,
int scaledWidth, int scaledHeight,
boolean preserveAlpha) {
System.out.println("resizing...");
Image scaled = originalImage.getScaledInstance(scaledWidth, -1, Image.SCALE_SMOOTH);
BufferedImage scaledBI = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = scaledBI.createGraphics();
g.drawImage(scaled, 0, 0, null);
g.dispose();
return scaledBI;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(newImg, 0, 0, this);
}
}
}
The Thread.sleep in the SwingWorker is intended to do two things:
Give time for the EDT to process the results from the process call and
Slow down the worker so that the results can be updated on the UI.
In my testing without it, the image was pretty much updated instantly.
I also recommend you take the time to better understand the paint process in Swing, start by having a look at:
Performing Custom Painting
Painting in AWT and Swing
The scaling mechanism you were using (and the one I've implemented) aren't the best solutions. I recommend having look at:
Java: maintaining aspect ratio of JPanel background image
Quality of Image after resize very low -- Java
for some better ideas.
You made a couple of mistakes, the first one is using 0 as scansize which should be the width of the image, also in the same line you should use the width and height instead of i and j.
newImg.setRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
There is one other mistake which I will let you find on your own, it should be obvious after you see the image with the above fixed line.
After scouring the internet for days, I found a Question that seemed to address my goal. (I'm trying to draw/edit an individual pixel in an image, and render it.) In said question, The ask-er requested code for a Black BufferedImage. The top Answer provided that code, and appears to work beautifully, until you try to change it to something other than black. Here's the Code:
package myProjectPackage;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.*;
public class Copypasta {
public static JFrame frame;
BufferedImage img;
public static int WIDTH = 500;
public static int HEIGHT = 500;
public Copypasta() {
}
public static void main(String[] a){
Copypasta t=new Copypasta();
frame = new JFrame("WINDOW");
frame.setVisible(true);
t.start();
frame.add(new JLabel(new ImageIcon(t.getImage())));
frame.pack();
// Better to DISPOSE than EXIT
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public Image getImage() {
return img;
}
public void start(){
img = new BufferedImage(WIDTH, HEIGHT,BufferedImage.TYPE_INT_RGB);
int[] pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
boolean running=true;
while(running){
BufferStrategy bs=frame.getBufferStrategy();
if(bs==null){
frame.createBufferStrategy(4);
return;
}
for (int i = 0; i < WIDTH * HEIGHT; i++)
pixels[i] = 0; //This is what i've been trying to change.
Graphics g= bs.getDrawGraphics();
g.drawImage(img, 0, 0, WIDTH, HEIGHT, null);
g.dispose();
bs.show();
}
}
}
I Apologize for the indentation errors. I promise it looks right in the editor.
When set to BufferedImage type ARGB, the black background disappears, causing me to believe that the start function isn't drawing to the Image at all, or the drawn image is not being drawn on the screen. Either way, There is something that I don't understand. If you have the time, I would appreciate some help Identifying What is going wrong, if not an explanation of why. Thank you all,
-Navi.
Link to Original Question: drawing your own buffered image on frame
Several things jump out, the use of BufferStrategy is probably overkill. Unless you absolutely must have control over the paint process, you really don't need it. Using a BufferStrategy also precludes the use of Swing based components which might or might not be an issue.
Trying to manipulate the pixel data directly is probably also a little overkill, instead you can use BufferedImage.setRGB(int, int, int), which allows you to set the color of the pixel at the specified x/y position, for example...
img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
img.setRGB(x, y, Color.RED.getRGB());
}
}
But, even this is a little overkill, the same thing can be achieved by using the provided 2D Graphics API...
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.dispose();
Which you will probably find is faster (not just from a coding point of view).
Take a look at:
Performing Custom Painting
Painting in AWT and Swing
2D Graphics
For more details...
Working example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestImage1 {
public static void main(String[] args) {
new TestImage1();
}
public TestImage1() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
public TestPane() {
img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
//for (int x = 0; x < img.getWidth(); x++) {
// for (int y = 0; y < img.getHeight(); y++) {
// img.setRGB(x, y, Color.RED.getRGB());
// }
//}
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(img, 0, 0, this);
g2d.dispose();
}
}
}
I have tried to save the JFrame as an image using the following approach.
try
{
BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
this.paint(image.getGraphics());
ImageIO.write(image,"png", new File("Test.png"));
}
catch(Exception exception)
{
//code
System.out.print("Exception unable to write image");
}
I am trying to save a screenshot as follows:
I would like to have even the title in my screenshot
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DividedSquare {
public static void main(String[] args) {
new DividedSquare();
}
public DividedSquare() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private TriangleShape baseTriangle;
private Color[] colors;
public TestPane() {
colors = new Color[]{Color.RED, Color.GREEN, Color.BLUE, Color.MAGENTA};
}
#Override
public void invalidate() {
super.invalidate();
baseTriangle = new TriangleShape(
new Point(0, 0),
new Point(getWidth(), 0),
new Point(getWidth() / 2, getHeight() / 2));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
String text[] = new String[]{
"123.123",
"456.789",
"012.315",
"678.921"
};
FontMetrics fm = g2d.getFontMetrics();
double angel = 0;
for (int index = 0; index < 4; index++) {
g2d.setColor(colors[index]);
Path2D rotated = rotate(baseTriangle, angel);
g2d.fill(rotated);
Rectangle bounds = rotated.getBounds();
int x = bounds.x + ((bounds.width - fm.stringWidth(text[0])) / 2);
int y = bounds.y + (((bounds.height - fm.getHeight()) / 2) + fm.getAscent());
g2d.setColor(Color.WHITE);
g2d.drawString(text[index], x, y);
angel += 90;
}
g2d.setColor(Color.BLACK);
g2d.drawLine(0, 0, getWidth(), getHeight());
g2d.drawLine(getWidth(), 0, 0, getHeight());
g2d.dispose();
try
{
BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
frame.paint(image.getGraphics());
ImageIO.write(image,"png", new File("Practice.png"));
}
catch(Exception exception)
{
//code
System.out.print("Exception to write image");
}
}
public Path2D rotate(TriangleShape shape, double angel) {
Rectangle bounds = shape.getBounds();
int x = bounds.width / 2;
int y = bounds.width / 2;
return new Path2D.Float(shape, AffineTransform.getRotateInstance(
Math.toRadians(angel),
x,
y));
}
}
public class TriangleShape extends Path2D.Double {
public TriangleShape(Point2D... points) {
moveTo(points[0].getX(), points[0].getY());
lineTo(points[1].getX(), points[1].getY());
lineTo(points[2].getX(), points[2].getY());
closePath();
}
}
}
But I the image does not get created. I am unable to understand why.
I looked at this but am unable to understand how to incorporate it in my case.
Edit
Based on comments, I tried using robot class but am unable to know where to call this function from. If I call this function from the paint() method, I am unable to get the colors and text.
void screenshot()
{
try
{
Robot robot = new Robot();
// Capture the screen shot of the area of the screen defined by the rectangle
Point p = frame.getLocationOnScreen();
System.out.print("point" + p);
BufferedImage bi=robot.createScreenCapture(new Rectangle((int)p.getX(),(int)p.getY(),frame.getWidth(),frame.getHeight()));
ImageIO.write(bi, "png", new File("imageTest.png"));
}
catch(Exception exception)
{
//code
System.out.print("Exception to write image");
}
}
There are at least two ways you might achieve this...
You Could...
Use Robot to capture a screen shot. For example
The problem with this is it takes a little effort to target the component you want to capture. It also only captures a rectangular area, so if the component is transparent, Robot won't respect this...
You Could...
Use printAll to render the component to your own Graphics context, typically from a BufferedImage
printAll allows you to print a component, because the intention is not to print this to the screen, printAll disables double buffering, making it more efficient to use when you don't want to render the component to the screen, such printing it to a printer...
Forexample
You can use Robot to capture screenshot. But it not gives Jframe Screenshot. We need to give correct coordinates and refer the frame. gFrame is my frame name and below code works for only Jframe area screenshot.
try {
Robot cap=new Robot();
Rectangle rec=new Rectangle(gFrame.getX(),gFrame.getY(),gFrame.getWidth(),gFrame.getHeight());
BufferedImage screenshot=cap.createScreenCapture(rec);
ImageIO.write(screenshot, "JPG",
new File("C:\\Users\\ruwan\\Downloads\\screenshot.jpg");
} catch (Exception e) {
e.printStackTrace();
}
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();
}
}
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();
}
}
}
This is a easy and short most developers using java code for image fade.
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
*
* #author ADMIN
*/
public class ImageFade extends JFrame {
ImageFade() {
setLayout(null);
JLabel l = new JLabel();
l.setBounds(0, 0, 100, 96);
add(l);
Thread tp = new Thread() {
#Override
public void run() {
for (int amp = 0; amp <= 500; amp++) {
try {
sleep(1);
try {
BufferedImage bim = ImageIO.read(new File("src/image/fade/image.png"));
BufferedImage nbim = new BufferedImage(bim.getWidth(), bim.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D createGraphics = nbim.createGraphics();
createGraphics.drawImage(bim, null, 0, 0);
RescaleOp r = new RescaleOp(new float[]{1f, 1f, 1f, (float) amp / 500}, new float[]{0, 0, 0, 0}, null);
BufferedImage filter = r.filter(nbim, null);
l.setIcon(new ImageIcon(filter));
} catch (Exception ex) {
System.err.println(ex);
}
} catch (InterruptedException ex) {
}
}
}
};
tp.start();
setUndecorated(true);
setBackground(new Color(0, 0, 0, 0));
setSize(100, 96);
setVisible(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setAlwaysOnTop(true);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
ImageFade fr = new ImageFade();
}
}
in this code you can see a thread code. in the thread this image will fade in.
the used image is stack overflow web page's logo image.
only by shown code the image will fade in.
Thread tp = new Thread() {
#Override
public void run() {
for (int amp = 0; amp <= 500; amp++) {
try {
sleep(1);
try {
BufferedImage bim = ImageIO.read(new File("src/image/fade/image.png"));
BufferedImage nbim = new BufferedImage(bim.getWidth(), bim.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D createGraphics = nbim.createGraphics();
createGraphics.drawImage(bim, null, 0, 0);
RescaleOp r = new RescaleOp(new float[]{1f, 1f, 1f, (float) amp / 500}, new float[]{0, 0, 0, 0}, null);
BufferedImage filter = r.filter(nbim, null);
l.setIcon(new ImageIcon(filter));
} catch (Exception ex) {
System.err.println(ex);
}
} catch (InterruptedException ex) {
}
}
}
};
tp.start();
This code is very simple to use.
This is not from any book, internet or etc. It is developed by me.
A normal image is not able to change alpha. By code : BufferedImage nbim = new BufferedImage(bim.getWidth(), bim.getHeight(), BufferedImage.TYPE_INT_ARGB); the image will convert to ARGB - Alpha, Red, Green, Blue (R,G,B,A) image.
So you can change the alpha of a image.
I am doing this for a project at school, in which much more functionality will be added later, but I am having trouble getting the basic setup done.
I tried doing this in C++ initially, but decided to switch to Java after reading some documentation on BufferedImage, but I am running into an issue with output. Essentially this is what I am designing the flow of the program to be:
1) Extract original image's (BMP image that is supplied in grayscale) grayscale values. 2) Create a currentImage variable to preserve the original image and perform the modifications to the image I intend to perform in the later stages of the project. 3) Create a reusable output method that will take the currentImage BufferedImage, and output it to a panel (and maybe a file as well.
Here is what I have so far, which currently results in nothing being outputted to the screen, and when I tried doing System logs, it is not setting the pixel values in my draw mechanism:
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;
#SuppressWarnings("serial")
public class ImageDriver extends JFrame {
DrawPanel paintPanel;
static int width = 1024, height = 768;
BufferedImage originalImage, currentImage;
File theImageFile;
int[][] imageData;
public ImageDriver() {
super("Image Processing");
setSize(width, height);
setDefaultCloseOperation(EXIT_ON_CLOSE);
paintPanel = new DrawPanel(width, height);
add(paintPanel);
}
public void updateImageDisplay() {
System.out.println("In updateImageDisplay!");
paintPanel.setImage(currentImage);
}
public void readImage() {
try {
theImageFile = new File("images/img1.bmp");
originalImage = ImageIO.read(theImageFile);
currentImage = originalImage;
}
catch (IOException e) {
e.printStackTrace();
}
//get a raster to extract grayscale values
Raster image_raster = currentImage.getData();
//get pixel by pixel
int[] pixel = new int[1];
int[] buffer = new int[1];
imageData = new int[image_raster.getWidth()][image_raster.getHeight()];
for(int i = 0 ; i < image_raster.getWidth() ; i++)
for(int j = 0 ; j < image_raster.getHeight() ; j++) {
pixel = image_raster.getPixel(i, j, buffer);
imageData[i][j] = pixel[0];
//System.out.println("Pixel at: " + i + " x " + j + ": " + imageData[i][j]);
}
}
public void increaseContrast() {
}
public static void main(String[] args) {
ImageDriver driver = new ImageDriver();
driver.setVisible(true);
driver.readImage();
driver.updateImageDisplay();
driver.increaseContrast();
driver.updateImageDisplay();
}
class DrawPanel extends JPanel {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
public DrawPanel(int width, int height) {
setPreferredSize(new Dimension(width, height));
}
public void setImage(BufferedImage image) {
System.out.println("In setImage!");
this.image = image;
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("in paintPanel component!");
g = image.getGraphics();
g.drawImage(image, 0, 0, null);
}
}
}
I have a hunch that it is because I am declaring image in my DrawPanel to be an empty image at first, and setImage is not properly copying over all of its contents upon assignment. I tried fiddling around with using this:
this.image.setData(image.getData());
but to no avail.
I missing something here? Or is a complete re-write if the mechanism in order?
Thank you for reading.
The first thing that jumps out at me is this (in your paintComponent method)...
g = image.getGraphics();
g.drawImage(image, 0, 0, null);
Basically, you are painting the image back to itself, instead you should do something like like...
g.drawImage(image, 0, 0, this);
Using the Graphics context you were passed