I'm trying to do a small image processing with Java. The user should be able to load an image and add some easy modifications to the image by clicking a button.
Loading and displaying the image is no problem but when I try to make a binary image out of it the repaint() method makes me a black image on the screen.
I think the problem is with the repaint()-method. I already used the search function and Google but I still have no idea what's wrong in my code.
That's what I have so far:
public class ImageProcessing extends JFrame implements ActionListener {
private JPanel imagePanel;
private JPanel buttonPanel;
private JButton binaryButton;
private JButton loadButton;
private BufferedImage image;
private final String WINDOW_TITLE = "Image Processing";
public ImageProcessing() {
createWindow();
}
private void createWindow() {
this.setTitle(WINDOW_TITLE);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(500, 500);
imagePanel = new ImagePanel();
buttonPanel = new JPanel();
this.add(imagePanel, BorderLayout.CENTER);
loadButton = new JButton("Load image");
loadButton.addActionListener(this);
buttonPanel.add(loadButton);
this.add(buttonPanel, BorderLayout.SOUTH);
binaryButton = new JButton("binary");
binaryButton.addActionListener(this);
buttonPanel.add(binaryButton);
this.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == this.loadButton) {
String filePath = getImageFile();
if (filePath != null) {
try {
image = ImageIO.read(new File(filePath));
// imageBackup = image;
} catch (IOException e1) {
e1.printStackTrace();
}
this.repaint();
}
} else if (e.getSource() == this.binaryButton) {
image = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
imagePanel = new ImagePanel();
this.repaint();
}
}
private String getImageFile() {
JFileChooser chooser = new JFileChooser();
int result = chooser.showOpenDialog(null);
File file = null;
if (result == JFileChooser.APPROVE_OPTION) {
file = chooser.getSelectedFile();
return file.getPath();
} else
return null;
}
class ImagePanel extends JPanel {
public void paint(Graphics g) {
g.drawImage(image, 0, 0, this);
}
}
}
I hope you can help me and explain what I'm doing wrong. Thanks in advance.
It's not clear what kind of image processing you're trying to do. The code..
image = new BufferedImage(
image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
..merely creates a new (blank) image with the byte binary type. You haven't drawn anything into it. That's why it's black.
To draw into it (for example to try to copy the original image), you can get a graphics context:
Graphics2D g = image.createGraphics();
And then copy with something like:
g.drawImage(otherImage, 0, 0, this);
I'm not sure whether or how Java will do a conversion from a full depth RGB image to TYPE_BYTE_BINARY. You might get an exception.
You are replacing the image panel instead of the image. Also, you're not performing the actual painting on the binary image. Here is an example how to convert the original image to a binary, it is based on the provided code:
else if (e.getSource() == this.binaryButton) {
BufferedImage mask = new BufferedImage(image.getWidth(),
image.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
Graphics g = mask.getGraphics();
g.drawImage(image, 0, 0, this);
g.dispose();
image = mask;
this.repaint();
}
Related
I need to rotate ImageIcon to buffered image in Java. I've tried every possible way, is there any way, I already tried to convert ImageIcon to bufferedImage.
I tried every possible StackOverflow solution
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
public class Test {
public static void main(String[] args) {
// Create GUI
GUI gui = new GUI();
// Schedule task; rotate img every 1s
Timer timer = new Timer(1000, e -> gui.rotateImg());
timer.setRepeats(true);
timer.start();
}
static class GUI extends JFrame {
// Web url for image of cute doggo
private static final String IMAGE_URL = "https://i.pinimg.com/736x/10/b2/6b/10b26b498bc3fcf55c752c4e6d9bfff7.jpg";
// Cache image and UI components for rotation
private BufferedImage image;
private ImageIcon icon;
private JLabel label;
// Create new JFrame
public GUI() {
// Config grame
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(700, 700);
setLocationRelativeTo(null);
URL url;
image = null;
try {
// Download + cache image from web
url = new URL(IMAGE_URL);
image = ImageIO.read(url);
} catch (IOException e) {
// Handle error downloading
System.out.println("Failed to read image due to: " + e.getMessage());
} finally {
// On success - create/cache UI components
if (image != null) {
// In this example I am using a label here to display an ImageIcon
// But at root the ImageIcon is holding a BufferedImage which is what we're modifying on rotation
add(label = new JLabel(icon = new ImageIcon(image)));
}
}
// Show configured JFrame
setVisible(true);
}
public void rotateImg() {
if (image == null) return;
// Rotate image
BufferedImage rotated = rotateImg(image, Math.toRadians(90));
// Add rotated image
icon.setImage(image = rotated);
// Repaint
label.revalidate();
label.repaint();
}
// SRC: https://www.delftstack.com/howto/java/java-rotate-image/
private BufferedImage rotateImg(BufferedImage img, double degrees) {
int w = img.getWidth(), h = img.getHeight();
BufferedImage imgCopy = new BufferedImage(w, h, img.getType());
Graphics2D g2d = imgCopy.createGraphics();
g2d.rotate(degrees, w / 2, h / 2);
g2d.drawImage(img, null, 0, 0);
return imgCopy;
}
}
}
I have written the following example to give something runnable of a problem I am having. When you press the button the controlWhichImage switches to 2. The problem is that when it switches from the original image to a copy the image disappears.
public class PainterDemo01 extends JPanel implements ActionListener {
BufferedImage createdImage;
BufferedImage img;
int controlWhichImage;
JFrame mainFrame;
JButton changePicture;
public PainterDemo01(){
changePicture = new JButton("Press");
changePicture.addActionListener(this);
controlWhichImage = 1;
mainFrame = new JFrame();
mainFrame.add(this);
this.add(changePicture);
mainFrame.setPreferredSize(new Dimension(600,600));
mainFrame.setVisible(true);
mainFrame.pack();
img = loadImage();
}
public BufferedImage loadImage(){
img = null;
try {
img = ImageIO.read(new File("/home/gerry/Desktop/100_0647.JPG"));
} catch (IOException e){
System.out.println("no file here");
}
return img;
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
loadImage();
if (createdImage == null){
this.createdImage = new BufferedImage(this.getWidth(),this.getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Graphics g2 = this.createdImage.getGraphics();
if (controlWhichImage == 1){
g2.drawImage(img,0,0,img.getWidth(),img.getHeight(),null);
g.drawImage(img, 0,0,img.getWidth(),img.getHeight(),null);
g2.dispose();
}
if (controlWhichImage == 2){
//Draw bufferedImage on to to JPanel
g.drawImage(this.createdImage,this.createdImage.getWidth(),this.createdImage.getHeight(),null);
}
}
#Override
public void actionPerformed(ActionEvent e){
controlWhichImage = 2;
repaint();
}
public static void main(String[] args) {
// TODO code application logic here
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new PainterDemo01().setVisible(true);
}
});
}
}
The problem is that getGraphics (or better named createGraphics) is called outside the if statement, also for 2, hence both causing a resource leak (as no g2.dispose is called), and also a clean slate.
if (controlWhichImage == 1) {
Graphics g2 = createdImage.getGraphics();
g2.drawImage(img,0,0,img.getWidth(),img.getHeight(),null);
g2.dispose();
}
Also do things like loading the image outside the paint code.
See this question if you want to know how to copy an BufferedImage:
How to copy BufferedImage
Of course! You have to go and paint the image at the outskirts. Please use this
g.drawImage(this.createdImage, 0, 0, this.createdImage.getWidth(),this.createdImage.getHeight(),null);
Use img obj since its already instantiated but not createdImage obj, createdImage contains null since its just declared but not instantiated. If you use createdImage obj means if you perform any operation upon createdImage obj then you will get NullPointerException.
Graphics g2 = this.img.getGraphics();
---------
Hi i am looking for a way to rescale my image and still show the entire image, so it isn't cut in half or something like that. I am also not allowed to use libraries of any sort. Im drawing the image with paintcomponent.
Is there any way how to do this properly?
I've tried this one already :
BufferedImage image = null;
try {
image = ImageIO.read(new File($question.getMediaFile().getPath())); /* Get the image */
Image scaled = image.getScaledInstance(350, 350, Image.SCALE_SMOOTH);
g.drawImage(scaled, w-350, 200, null);
} catch (IOException e) {
e.printStackTrace();
}
This resizes my image but doesn't show the entire image, i would like to rescale it to an image with 300*300 or 350*350 size or something like that.
Thanks!
Using the getScaledInstance() method works fine for me. Here's the code i was testing with:
public class Resize {
public static void main(String[] args) throws Exception {
final Image logo = ImageIO.read(new URL("http://cdn.sstatic.net/stackexchange/img/logos/so/so-logo.png"));
final Dimension dim = new Dimension(logo.getWidth(null), logo.getHeight(null));
final JFrame frame = new JFrame();
frame.add(new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(logo.getScaledInstance(dim.width, dim.height, 0), 0, 0, this);
}
});
final JSlider xSlider = new JSlider(JSlider.HORIZONTAL, 1, dim.width*3, dim.width);
final JSlider ySlider = new JSlider(JSlider.VERTICAL, 1, dim.height*3, dim.height);
ChangeListener cl = new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
dim.width = xSlider.getValue();
dim.height = ySlider.getValue();
frame.repaint();
}
};
xSlider.addChangeListener(cl);
ySlider.addChangeListener(cl);
frame.add(xSlider, "South");
frame.add(ySlider, "East");
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
I am trying to create an image viewer the the idea is that the viewer will pop up with one image a random button and a reset button to let the user to click the button and cycle through a list of different images randomly. I can open the viewer but cant get the viewer to rotate the images. here is the code. I would be grateful for any help
import java.awt.*;
import javax.swing.*;
public class CreateImage extends JFrame {
private JButton jbtRandom = new JButton("Random");
private JButton jbtReset = new JButton ("Reset");
public CreateImage() {
JPanel panel = new JPanel();
panel.add(jbtRandom);
panel.add(jbtReset);
Image image1 = new ImageIcon("kobe.jpg").getImage();
Image image2 = new ImageIcon("joe.jpg").getImage();
Image image3 = new ImageIcon("sidney.jpg").getImage();
Image image4 = new ImageIcon("bugs.gif").getImage();
Image image5 = new ImageIcon("mac.jpg").getImage();
Image image6 = new ImageIcon("snooki.jpg").getImage();
setLayout(new GridLayout(2, 0, 5, 5));
add(new ImageViewer(image1));
/*add(new ImageViewer(image2));// <== extra lines form first viewer attempt
add(new ImageViewer(image3)); //, <== which showed all images at once.
add(new ImageViewer(image4));// <== only need one image and to flip
add(new ImageViewer(image5));// <== to a random image
add(new ImageViewer(image6));// <== */
}
public class ImageViewer extends JPanel {
private java.awt.Image image;
private boolean stretched = true;
private int xCoordinate;
private int yCoordinate;
public ImageViewer() {
}
public ImageViewer(Image image) {
this.image = image;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null)
if (isStretched())
g.drawImage(image, xCoordinate, yCoordinate, getWidth(), getHeight(), this);
else
g.drawImage(image, xCoordinate, yCoordinate, this);
}
public java.awt.Image getImage() {
return image;
}
public void setImage(java.awt.Image image) {
this.image = image;
repaint();
}
public boolean isStretched() {
return stretched;
}
public void setStretched(boolean stretched) {
this.stretched = stretched;
repaint();
}
public int getXCoordinate() {
return xCoordinate;
}
public void setXCoodinate(int xCoordinate) {
this.xCoordinate = xCoordinate;
}
public int getYCoordinate() {
return xCoordinate;
}
public void setYCoodinate(int yCoordinate) {
this.yCoordinate = yCoordinate;
repaint();
}
}
public static void main(String[] args) {
JFrame frame = new CreateImage();
frame.setTitle("Random Image-Click The Button");
frame.add(new JButton("Random"));
frame.add(new JButton("Reset"));
frame.setSize(400, 320);
frame.setLocationRelativeTo(null); //Center Frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Here are some steps you need to take to get started:
1) Instead of just creating and throwing away the images. Put them somewhere - like in a List or Map.
2) Add an event handler to your Random button.
3) On clicking that button, choose and show a new image from your List or Map.
Once you've done that post another more specific question if you're still stuck. You're quite far away from getting your end-goal at the moment so for now just focus on responding to a user event (clicking your buttons) to start with.
Refer to this to get started.
I have a java programme than when a button is clicked it updates the image on screen to the according image. this will work for the first 15 or so clicks then it causes a java heapspace error. I think it is because of the way I am updating the jpanel that contains the bufferedimage but not sure what the reason is. My code to get make the JPanel contain the new image is,
public class extraScreenPanel {
static JPanel screenPanel = new JPanel(new BorderLayout());
public static JPanel extraScreenPanel(int dispNum)
{
JLabel label = new JLabel("" + dispNum + "");
label.setPreferredSize(new Dimension(800, 600));
//label.setUI( new VerticalLabelUI(true) );
label.setVerticalAlignment( SwingConstants.TOP );
screenPanel = imgDisp(dispNum);
label.setForeground(Color.white);
label.setFont(new Font("Serif", Font.BOLD, 200));
screenPanel.add(label, BorderLayout.PAGE_END );
return screenPanel;
}
public static JPanel imgDisp(int picNum) {
/* String url[] = new String[5000];
String part1;
url[0] = "C:/PiPhotoPic/pic16.jpg";
for(Integer i=1;i<5000;i++){
if(i<10){part1 = "C:/temp/new0000000";}
else if(i<100){part1 = "C:/temp/new000000";}
else if(i<1000){part1 = "C:/temp/new00000";}
else {part1 = "C:/temp/new00000";}
String num = Integer.toString(i);
url[i]= part1 + num + ".jpg";
}
if(picNum<0){picNum=0;}
String ref = url[picNum];*/ //this code is just to get specific ref for image location
BufferedImage loadImg = loadImage(ref);
JImagePanel panel = new JImagePanel(loadImg, 0, 0);
panel.setPreferredSize(new Dimension(800, 600));
return panel;
}
public static class JImagePanel extends JPanel{
private BufferedImage image;
int x, y;
public JImagePanel(BufferedImage image, int x, int y) {
super();
this.image = image;
this.x = x;
this.y = y;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, x, y, null);
}
}
public static BufferedImage loadImage(String ref) {
BufferedImage bimg = null;
try {
bimg = javax.imageio.ImageIO.read(new File(ref));
} catch (Exception e) {
e.printStackTrace();
}
BufferedImage bimg2 = resize(bimg,800,600);
return bimg2;
}
public static BufferedImage resize(BufferedImage img, int newW, int newH) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage dimg = dimg = new BufferedImage(newW, newH, img.getType());
Graphics2D g = dimg.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);
g.dispose();
return dimg;
}
}
And the code that updates my gui is, it works by removing the panel from its containg panel and then readding it to it.
picPanel = imgDisp.imgDisp(num);
repaintPicPanel();
public static void repaintPicPanel()
{
picPanel.removeAll();
menuPanel.remove(picPanel);;
menuPanel.add(picPanel, BorderLayout.LINE_START);
}
It's almost impossible to read your code but I would wager that since the images are tied into the JPanels and you never properly dispose of the panels or images they're hanging around and that causes your error. I would also try to do everything inline so that instead of removing the whole panel and replacing it with a new one, you just delete the image from the panel and replace that with a new one.