How to paint GUI with Binary Image Processing? - java

I'm working on image processing but I can't find a way to paint GUI RGB with binary image reading. I'm stuck with paintComponent area.
I can read file but cant paint RGB values to GUI. Can somebody guide me please?
This is what I have done so far:
private int ws;
private FileInputStream fis;
mybin(){
try {
fis = new FileInputStream("mybin.bin");
String mn = getMagicNumber();
System.out.println(mn);
skipWhitespace();
int width = readNumber();
System.out.println(width);
skipWhitespace();
int height = readNumber();
System.out.println(height);
skipWhitespace();
int maxNum = readNumber();
System.out.println(maxNum);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
catch(IOException e2) {}
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(600,600);
this.setVisible(true);
}
private String getMagicNumber() {
byte [] magicNum = new byte[2];
try {
fis.read(magicNum);
} catch (IOException e) {
e.printStackTrace();
}
return new String(magicNum);
}
private void skipWhitespace() {
try {
ws = fis.read();
while(Character.isWhitespace(ws))
ws = fis.read();
} catch (IOException e) {
e.printStackTrace();
}
}
private int readNumber() {
String wstr = "";
try {
while(!Character.isWhitespace(ws)) {
//while(Character.isDigit(ws))
wstr = wstr + (ws-'0'/*48*/);
ws = fis.read();
}
}catch(IOException e2) {}
System.out.println(wstr);
return Integer.parseInt(wstr);
}
class DrawingPanel extends JPanel{
#Override
public void paintComponent(Graphics g) {
}
}
public static void main(String [] args) {
new mybin();
}
}

If you have a data structure to hold RGB values and want to paint them on the screen:
First you should create an image of them, first. Something like this:
// Create an image, with given dimensions, and RGB palette...
final BufferedImage image = new BufferedImage( width, height, BufferedImage.TYPE_INT_RGB);
// Paint the RGB values (EG from arrays) to the image
for (int x = 0; x < width; ++x)
for (int y = 0; y < height; ++y)
{
// Convert the R,G,B values to a single int
final int rgb = r[x,y]*0x10000 + g[x,y]*1x100 + b[x,y];
// Color the pixel...
image.setRGB(x, y, rgb);
}
Then display it on your GUI.
This could be done, creating a special component, and performing painting, see c0der's answer.
Or you could just create an Icon, and add it to any JLabel:
label.setIcon(new ImageIcon(image));

Painting a BufferedImage can be as simple as:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class ImageFrame extends javax.swing.JFrame {
public ImageFrame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(new GraphicsPanel());
pack();
setVisible(true);
}
public static void main(final String[] args){
new ImageFrame();
}
}
class GraphicsPanel extends JPanel {
private BufferedImage image;
//always use publicly accessible resources when posting mcve
private final String imagePath = "https://upload.wikimedia.org/wikipedia/commons/3/3f/Crystal_Project_bug.png";
GraphicsPanel(){
try {
image = ImageIO.read(new URL(imagePath)); //or image = ImageIO.read(new File(...));
} catch(final IOException e) {e.printStackTrace(); }
setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
}
#Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
}

Related

How to Draw an BufferedImage to a JPanel

I am trying to use some sort of draw method to draw a sprite image to my subclass of JPanel called AnimationPanel. I have created a Spritesheet class which can generate a BufferedImage[] that contains all of the sprites in the sheet. In my AnimationPanel class, which implements Runnable, I am getting that BufferedImage[] from the spritesheet instantiated in the AnimationPanel constructor. I want to be able to loop through this array and display each sprite to the screen. How would I do this? Here are my AnimationPanel and Spritesheet classes.
AnimationPanel
package com.kahl.animation;
import javax.swing.JPanel;
public class AnimationPanel extends JPanel implements Runnable {
//Instance Variables
private Spritesheet sheet;
private int currentFrame;
private Thread animationThread;
private BufferedImage image;
public AnimationPanel(Spritesheet aSheet) {
super();
sheet = aSheet;
setPreferredSize(new Dimension(128,128));
setFocusable(true);
requestFocus();
}
public void run() {
BufferedImage[] frames = sheet.getAllSprites();
currentFrame = 0;
while (true) {
frames[currentFrame].draw(); //some implementation still necessary here
currentFrame++;
if (currentFrame >= frames.length) {
currentFrame = 0;
}
}
}
public void addNotify() {
super.addNotify();
if (animationThread == null) {
animationThread = new Thread(this);
animationThread.start();
}
}
}
Spritesheet
package com.kahl.animation;
import java.awt.image.BufferedImage;
import java.imageio.ImageIO;
import java.io.IOException;
import java.io.File;
public class Spritesheet {
//Instance Variables
private String path;
private int frameWidth;
private int frameHeight;
private int framesPerRow;
private int frames;
private BufferedImage sheet = null;
//Constructors
public Spritesheet(String aPath,int width,int height,int fpr, int numOfFrames) {
path = aPath;
frameWidth = width;
frameHeight = height;
framesPerRow = fpr;
frames = numOfFrames;
try {
sheet = ImageIO.read(getClass().getResourceAsStream());
} catch (IOException e) {
e.printStackTrace();
}
}
//Methods
public int getHeight() {
return frameWidth;
}
public int getWidth() {
return frameWidth;
}
public int getFramesPerRow() {
return framesPerRow;
}
private BufferedImage getSprite(int x, int y, int h, int w) {
BufferedImage sprite = sheet.getSubimage(x,y,h,w);
}
public BufferedImage[] getAllSprites() {
BufferedImage[] sprites = new BufferedImage[frames];
int y = 0;
for (int i = 0; i < frames; i++) {
x = i * frameWidth;
currentSprite = sheet.getSprite(x,y,frameHeight,frameWidth);
sprites.add(currentSprite);
}
return sprites;
}
}
I'd encourage the use of a javax.swing.Timer to control the frame rate, rather than an uncontrolled loop
Once the timer "ticks", you need to increment the current frame, get the current image to be rendered and call repaint on the JPanel
Use Graphics#drawImage to render the image.
See...
Painting in AWT and Swing
Performing Custom Painting
How to use Swing Timers
Graphics#drawImage(Image, int, int, ImageObserver)
for more details
There is a cascading series of issues with your Spritesheet class, apart from the fact that it won't actually compile, there are issues with you returning the wrong values from some methods and relying on values which are better calculated...
I had to modify your code so much, I can't remember most of them
public int getHeight() {
return frameWidth;
}
and
public BufferedImage[] getAllSprites() {
BufferedImage[] sprites = new BufferedImage[frames];
int y = 0;
for (int i = 0; i < frames; i++) {
x = i * frameWidth;
currentSprite = sheet.getSprite(x,y,frameHeight,frameWidth);
sprites.add(currentSprite);
}
return sprites;
}
Stand out as two main examples...
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.image.BufferedImage;
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 TestSpriteSheet {
public static void main(String[] args) {
new TestSpriteSheet();
}
public TestSpriteSheet() {
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 class TestPane extends JPanel {
private Spritesheet spritesheet;
private BufferedImage currentFrame;
private int frame;
public TestPane() {
spritesheet = new Spritesheet("/Sheet02.gif", 240, 220);
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
currentFrame = spritesheet.getSprite(frame % spritesheet.getFrameCount());
repaint();
frame++;
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(240, 220);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (currentFrame != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - currentFrame.getWidth()) / 2;
int y = (getHeight() - currentFrame.getHeight()) / 2;
g2d.drawImage(currentFrame, x, y, this);
g2d.dispose();
}
}
}
public class Spritesheet {
//Instance Variables
private String path;
private int frameWidth;
private int frameHeight;
private BufferedImage sheet = null;
private BufferedImage[] frameImages;
//Constructors
public Spritesheet(String aPath, int width, int height) {
path = aPath;
frameWidth = width;
frameHeight = height;
try {
sheet = ImageIO.read(getClass().getResourceAsStream(path));
frameImages = getAllSprites();
} catch (IOException e) {
e.printStackTrace();
}
}
public BufferedImage getSprite(int frame) {
return frameImages[frame];
}
//Methods
public int getHeight() {
return frameHeight;
}
public int getWidth() {
return frameWidth;
}
public int getColumnCount() {
return sheet.getWidth() / getWidth();
}
public int getRowCount() {
return sheet.getHeight() / getHeight();
}
public int getFrameCount() {
int cols = getColumnCount();
int rows = getRowCount();
return cols * rows;
}
private BufferedImage getSprite(int x, int y, int h, int w) {
BufferedImage sprite = sheet.getSubimage(x, y, h, w);
return sprite;
}
public BufferedImage[] getAllSprites() {
int cols = getColumnCount();
int rows = getRowCount();
int frameCount = getFrameCount();
BufferedImage[] sprites = new BufferedImage[frameCount];
int index = 0;
System.out.println("cols = " + cols);
System.out.println("rows = " + rows);
System.out.println("frameCount = " + frameCount);
for (int row = 0; row < getRowCount(); row++) {
for (int col = 0; col < getColumnCount(); col++) {
int x = col * getWidth();
int y = row * getHeight();
System.out.println(index + " " + x + "x" + y);
BufferedImage currentSprite = getSprite(x, y, getWidth(), getHeight());
sprites[index] = currentSprite;
index++;
}
}
return sprites;
}
}
}
Remember, animation is the illusion of change over time. You need to provide a delay between each frame of the animation, long enough for the user to recognise it, but short enough to make the animation look smooth.
In the above example, I've used 100 milliseconds, simply as an arbitrary value. It could be possible to use something more like 1000 / spritesheet.getFrameCount(), which will allow a full second for the entire animation (all the frames within one second).
You might need to use different values, for longer or short animations, depending on your needs
Here's some generic code for drawing an image to a JPanel. This method is called to paint your JPanel component.
public void paintComponent (Graphics g)
{
super.paintComponent(g);
//I would have image be a class variable that gets updated in your run() method
g.drawImage(image, 0, 0, this);
}
I may also modify run() to look something like this:
public void run() {
BufferedImage[] frames = sheet.getAllSprites();
currentFrame = 0;
while (true) {
image = frames[currentFrame];
this.repaint(); //explicitly added "this" for clarity, not necessary.
currentFrame++;
if (currentFrame >= frames.length) {
currentFrame = 0;
}
}
}
In regards to only repainting part of the component, it gets a little more complicated
public void run() {
BufferedImage[] frames = sheet.getAllSprites();
currentFrame = 0;
while (true) {
image = frames[currentFrame];
Rectangle r = this.getDirtyRect();
this.repaint(r);
currentFrame++;
if (currentFrame >= frames.length) {
currentFrame = 0;
}
}
}
public Rectangle getDirtyRect() {
int minX=0; //calculate smallest x value affected
int maxX=0; //calculate largest x value affected
int minY=0; //calculate smallest y value affected
int maxY=0; //calculate largest y value affected
return new Rectangle(minX,minY,maxX,maxY);
}

Select, Copy and Paste Images

What I want my app to do:
1 - Select an area of Image and get the coordinates. This code below should do this:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
public class ScreenCaptureRectangle {
Rectangle captureRect;
ScreenCaptureRectangle(final BufferedImage screen) {
final BufferedImage screenCopy = new BufferedImage(
screen.getWidth(),
screen.getHeight(),
screen.getType());
final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
JScrollPane screenScroll = new JScrollPane(screenLabel);
screenScroll.setPreferredSize(new Dimension(
(int)(screen.getWidth()/3),
(int)(screen.getHeight()/3)));
JPanel panel = new JPanel(new BorderLayout());
panel.add(screenScroll, BorderLayout.CENTER);
final JLabel selectionLabel = new JLabel(
"Drag a rectangle in the screen shot!");
panel.add(selectionLabel, BorderLayout.SOUTH);
repaint(screen, screenCopy);
screenLabel.repaint();
screenLabel.addMouseMotionListener(new MouseMotionAdapter() {
Point start = new Point();
#Override
public void mouseMoved(MouseEvent me) {
start = me.getPoint();
repaint(screen, screenCopy);
selectionLabel.setText("Start Point: " + start);
screenLabel.repaint();
}
#Override
public void mouseDragged(MouseEvent me) {
Point end = me.getPoint();
captureRect = new Rectangle(start,
new Dimension(end.x-start.x, end.y-start.y));
repaint(screen, screenCopy);
screenLabel.repaint();
selectionLabel.setText("Rectangle: " + captureRect);
}
});
JOptionPane.showMessageDialog(null, panel);
System.out.println("Rectangle of interest: " + captureRect);
}
public void repaint(BufferedImage orig, BufferedImage copy) {
Graphics2D g = copy.createGraphics();
g.drawImage(orig,0,0, null);
if (captureRect!=null) {
g.setColor(Color.RED);
g.draw(captureRect);
g.setColor(new Color(255,255,255,150));
g.fill(captureRect);
}
g.dispose();
}
public static void main(String[] args) throws Exception {
Robot robot = new Robot();
final Dimension screenSize = Toolkit.getDefaultToolkit().
getScreenSize();
final BufferedImage screen = robot.createScreenCapture(
new Rectangle(screenSize));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ScreenCaptureRectangle(screen);
}
});
}
}
2 - get the coordinates and use it on getSubimage method.
double w = captureRect.getWidth();
double h = captureRect.getHeight();
double x = captureRect.getX();
double y = captureRect.getY();
int W = (int) w;
int H = (int) h;
int X = (int) x;
int Y = (int) y;
BufferedImage selectImg = screen.getSubimage(x, y, w, h);
3 - this code create a new image file and copy the imageselected.
BufferedImage img = new BufferedImage ( 5000, 5000, BufferedImage.TYPE_INT_RGB );
img.createGraphics().drawImage(selectImg, 0, 0, null);
File final_image = new File("C:/Final.jpg");
ImageIO.write(img, "jpeg", final_image);
The idea of app is:
- Select an area of the image.
- Copy that image and paste in other file. ( when I pressed any button )
- The program will continue run until I press another button.
- Every image that I copy the program will paste it beside the last one.
I think I am near to the solution. Can any one help me to "connect the parts" ?
Start by taking a look at:
How to Write a Mouse Listener
How to Use Buttons, Check Boxes, and Radio Buttons
How to Write an Action Listeners
Performing Custom Painting
Writing/Saving an Image
You need to take the concepts you have and rework them into a coherent workable solution. That is, provide functionality between the areas you need (selecting a region and saving the file) so that they work cleanly together...
The following example takes a screenshot, allows you to select an area, click save and the file will be saved. The example checks to see how many files are already in the current directory and increments the count by 1 so you are not overwriting the existing files...
import java.awt.AWTException;
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.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
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.FileFilter;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ScreenImage {
public static void main(String[] args) {
new ScreenImage();
}
public ScreenImage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
try {
Robot robot = new Robot();
final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
final BufferedImage screen = robot.createScreenCapture(new Rectangle(screenSize));
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane(screen));
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (AWTException exp) {
exp.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
public TestPane(BufferedImage image) {
this.master = image;
setLayout(new BorderLayout());
final ImagePane imagePane = new ImagePane(image);
add(new JScrollPane(imagePane));
JButton btnSave = new JButton("Save");
add(btnSave, BorderLayout.SOUTH);
btnSave.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
BufferedImage img = imagePane.getSubImage();
master = append(master, img);
File save = new File("Capture.png");
ImageIO.write(master, "png", save);
imagePane.clearSelection();
JOptionPane.showMessageDialog(TestPane.this, save.getName() + " was saved", "Saved", JOptionPane.INFORMATION_MESSAGE);
} catch (IOException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(TestPane.this, "Failed to save capture", "Error", JOptionPane.ERROR_MESSAGE);
}
}
public BufferedImage append(BufferedImage master, BufferedImage sub) {
// Create a new image which can hold both background and the
// new image...
BufferedImage newImage = new BufferedImage(
master.getWidth() + sub.getWidth(),
Math.max(master.getHeight(), sub.getHeight()),
BufferedImage.TYPE_INT_ARGB);
// Get new image's Graphics context
Graphics2D g2d = newImage.createGraphics();
// Draw the old background
g2d.drawImage(master, 0, 0, null);
// Position and paint the new sub image...
int y = (newImage.getHeight() - sub.getHeight()) / 2;
g2d.drawImage(sub, master.getWidth(), y, null);
g2d.dispose();
return newImage;
}
});
}
}
public class ImagePane extends JPanel {
private BufferedImage background;
private Rectangle selection;
public ImagePane(BufferedImage img) {
background = img;
MouseAdapter ma = new MouseAdapter() {
private Point clickPoint;
#Override
public void mousePressed(MouseEvent e) {
clickPoint = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
Point dragPoint = e.getPoint();
int x = Math.min(clickPoint.x, dragPoint.x);
int y = Math.min(clickPoint.y, dragPoint.y);
int width = Math.abs(clickPoint.x - dragPoint.x);
int height = Math.abs(clickPoint.y - dragPoint.y);
selection = new Rectangle(x, y, width, height);
repaint();
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
public void clearSelection() {
selection = null;
repaint();
}
public BufferedImage getSubImage() {
BufferedImage img = null;
if (selection != null) {
img = background.getSubimage(selection.x, selection.y, selection.width, selection.height);
}
return img;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(background.getWidth(), background.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g2d.drawImage(background, x, y, this);
if (selection != null) {
Color stroke = UIManager.getColor("List.selectionBackground");
Color fill = new Color(stroke.getRed(), stroke.getGreen(), stroke.getBlue(), 128);
g2d.setColor(fill);
g2d.fill(selection);
g2d.setColor(stroke);
g2d.draw(selection);
}
g2d.dispose();
}
}
}
So apart from rendering the selection the hardest part would be generating the resulting image...
Basically, this done by creating a new BufferedImage and painting the old image and the new, sub, image together.
public BufferedImage append(BufferedImage master, BufferedImage sub) {
// Create a new image which can hold both background and the
// new image...
BufferedImage newImage = new BufferedImage(
master.getWidth() + sub.getWidth(),
Math.max(master.getHeight(), sub.getHeight()),
BufferedImage.TYPE_INT_ARGB);
// Get new image's Graphics context
Graphics2D g2d = newImage.createGraphics();
// Draw the old background
g2d.drawImage(master, 0, 0, null);
// Position and paint the new sub image...
int y = (newImage.getHeight() - sub.getHeight()) / 2;
g2d.drawImage(sub, master.getWidth(), y, null);
g2d.dispose();
return newImage;
}
The example replaces the previous (master) image with the one created here, so it will constantly be appending new images to the end of it...
You need more listeners for button pressed and released.. some lines in the mouseMoved also better placed in mousePressed.
You would want to update your captureRect when you release the mouse (in mouseReleased method).
Then you just write it to the file. You may adjust other things according to your needs.
And for clarity maybe it's better to add a save button into your UI.
public class ScreenCaptureRectangle {
Rectangle captureRect;
Point start = new Point();
SimpleDateFormat sdf;
ScreenCaptureRectangle(final BufferedImage screen) {
sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
final BufferedImage screenCopy = new BufferedImage(
screen.getWidth(),
screen.getHeight(),
screen.getType());
final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
JScrollPane screenScroll = new JScrollPane(screenLabel);
screenScroll.setPreferredSize(new Dimension(
(int) (screen.getWidth() / 3),
(int) (screen.getHeight() / 3)));
JPanel panel = new JPanel(new BorderLayout());
panel.add(screenScroll, BorderLayout.CENTER);
JButton btnSave = new JButton("SAVE");
btnSave.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
double w = captureRect.getWidth();
double h = captureRect.getHeight();
double x = captureRect.getX();
double y = captureRect.getY();
int W = (int) w;
int H = (int) h;
int X = (int) x;
int Y = (int) y;
BufferedImage selectImg = screen.getSubimage(X, Y, W, H);
try {
String fName = generateFileName();
if (fName != null) {
File f = new File(fName);
if (f.createNewFile()) {
ImageIO.write(selectImg, "jpg", f);
}
}
} catch (IOException ex) {
Logger.getLogger(ScreenCaptureRectangle.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
panel.add(btnSave, BorderLayout.AFTER_LAST_LINE);
final JLabel selectionLabel = new JLabel(
"Drag a rectangle in the screen shot!");
panel.add(selectionLabel, BorderLayout.SOUTH);
repaint(screen, screenCopy);
screenLabel.repaint();
screenLabel.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent me) {
Point end = me.getPoint();
captureRect = new Rectangle(start,
new Dimension(end.x - start.x, end.y - start.y));
repaint(screen, screenCopy);
screenLabel.repaint();
selectionLabel.setText("Rectangle: " + captureRect);
}
});
screenLabel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent me) {
start = me.getPoint();
repaint(screen, screenCopy);
selectionLabel.setText("Start Point: " + start);
screenLabel.repaint();
}
#Override
public void mouseReleased(MouseEvent me) {
int endX = me.getX();
int endY = me.getY();
if (endX > start.x && endY > start.y) {
captureRect = new Rectangle(start.x, start.y, endX-start.x, endY-start.y);
System.out.println("Rectangle of interest: " + captureRect);
}
}
});
JOptionPane.showMessageDialog(null, panel);
}
private String generateFileName() {
return new StringBuilder("screencrop_").append(sdf.format(new Date())).append(".jpg").toString();
}
public void repaint(BufferedImage orig, BufferedImage copy) {
Graphics2D g = copy.createGraphics();
g.drawImage(orig, 0, 0, null);
if (captureRect != null) {
g.setColor(Color.RED);
g.draw(captureRect);
g.setColor(new Color(255, 255, 255, 150));
g.fill(captureRect);
}
g.dispose();
}
public static void main(String[] args) throws Exception {
Robot robot = new Robot();
final Dimension screenSize = Toolkit.getDefaultToolkit().
getScreenSize();
final BufferedImage screen = robot.createScreenCapture(
new Rectangle(screenSize));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ScreenCaptureRectangle(screen);
}
});
}
}

ImageObserver not working

Can someone tell me what I need to do to get ImageObserver to work. I thought this would work. I'd like it to print a message when the image loads but it doesn't... What am I doing wrong? This can probably be answered easily.
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ImageTest extends JPanel implements ImageObserver {
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y,
int width, int height) {
if((infoflags & ALLBITS) == 0) {
System.out.println("Processing still");
return true;
} else {
System.out.println("Done processing");
return false;
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, this);
}
BufferedImage img;
public ImageTest (){
try {
img = ImageIO.read(new File("res/soccer-ball.jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String args[]) {
JFrame f = new JFrame();
f.setContentPane(new ImageTest());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(1000, 1000);
f.setVisible(true);
}
}
Instead of putting it in the drawImage simply use the ToolKit to process your image where you will use the instance of your ImageObserver to prepare the image
change this:
try {
img = ImageIO.read(new File("res/soccer-ball.jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
to:
public class ImageTest extends JPanel implements ImageObserver {
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y,
int width, int height) {
if((infoflags & ALLBITS) == 0) {
System.out.println("Processing still");
return true;
} else {
System.out.println("Done processing");
repaint();
return false;
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, this);
}
Image img;
public ImageTest (){
Toolkit toolkit = Toolkit.getDefaultToolkit();
img = toolkit.getImage("res/soccer-ball.jpg");
toolkit.prepareImage(img, -1, -1, this);
}
public static void main(String args[]) {
JFrame f = new JFrame();
f.setContentPane(new ImageTest());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(1000, 1000);
f.setVisible(true);
}
}
Where you need to repaint the JPanel when the image is finished processing or else the image wont show.
For one thing, JPanel already implements ImageObserver, so overriding imageUpdate in this way likely breaks the panel's normal functionality.
Also, you implement ImageObserver but never subscribe/register to observe anything.
Try this:
...
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
if ((infoflags & ALLBITS) == 0) {
System.out.println("Processing still");
} else {
System.out.println("Done processing");
}
return super.imageUpdate(img, infoflags, x, y, w, h);
}
...
public ImageTest() {
try {
img = ImageIO.read(new File("res/soccer-ball.jpg"));
prepareImage(img, this);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
...

Set color of a pixel in an image

Hey,I'm trying to make a program which loads a colored image as grayscale on canvas and then returns the color to the pixels clicked.
I'm stuck here when the setrgb() method is not doing what its supposed to. I have copied the color from original image by getRGB() and am using setRGB() to assign it to a new image.
I have tried to output both the pixel color values but they are not same.
Please help me out with this.
Here's the code so far:
import java.awt.image.*;
import javax.imageio.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import java.awt.*;
import java.applet.*;
#SuppressWarnings("serial")
public class BlackWHite extends Applet implements MouseListener
{
String str;
int x=0,y=0;
BufferedImage bimg = null;
BufferedImage nimg = null;
BufferedImage image=null;
double image_width =300;
double image_height=300;
private Image img;
public void init()
{
img = null;
str = JOptionPane.showInputDialog(null, "Enter file location : ",
"Choose Image", 1);
BufferedImage image=null;
try {
image = ImageIO.read(new File(str));
} catch (IOException e) {
e.printStackTrace();
}
//getting width and height of image
image_width = image.getWidth();
image_height = image.getHeight();
BufferedImage img = image;
//drawing a new image
bimg = new BufferedImage((int)image_width, (int)image_height,
BufferedImage.TYPE_BYTE_GRAY);
Graphics2D gg = bimg.createGraphics();
gg.drawImage(img, 0, 0, img.getWidth(null), img.getHeight(null), null);
nimg = new BufferedImage((int)image_width, (int)image_height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = nimg.createGraphics();
g.drawImage(img, 0, 0, img.getWidth(null), img.getHeight(null), null);
addMouseListener(this);
}
public void loadImage()
{
try {
img = getImage(getCodeBase(), "blackwhiteimage.jpg");
} catch(Exception e) {
}
}
public void paint(Graphics g)
{
try {
image = ImageIO.read(new File(str));
} catch (IOException e) {
e.printStackTrace();
}
convert(); //converting the image
if (img == null)
loadImage(); //draw
g.drawImage(img, 0, 0, this);
int c = image.getRGB(x,y);
int red = (c & 0x0000FFFF) >> 16;
int green = (c & 0x0000FFFF) >> 8;
int blue = c & 0x0000FFFF;
c=(red << 16) | (green << 8) | blue;
System.out.print("c="+c);
nimg=bimg;
nimg.setRGB(x,y,c);
try {
ImageIO.write(nimg, "jpg", new File("pixelcolor.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
g.drawImage(nimg, 0, 0, this);
int f = nimg.getRGB(x,y);
System.out.println("f="+f);
}
void convert() {
try {
//saving black and white image onto drive
ImageIO.write(bimg, "jpg", new File("blackwhiteimage.jpg"));
} catch (Exception e) {
System.out.println(e);
}
}
#Override
public void mouseClicked(MouseEvent me) {
x = me.getX();
y = me.getY();
repaint();
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
The fundamental problem is that you are trying to set the colour of the image in gray scale colour space. That is not the only bug in the applet, but you can start with it. Try using another way to convert the image to gray scale while keeping it in RGBA, such as those shown here: convert a RGB image to grayscale Image reducing the memory in java

Trying to paint image to JFrame with Java BufferedImage, Graphics

I'm trying to capture the screen and then paint the image to a JFrame recursively while scaling the image (to create that effect you get when you look at a mirror in a mirror).
I'm having trouble with my code - it doesn't paint any graphics. What am I doing wrong?
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
public class ScreenCapture extends JFrame {
BufferedImage screenCapture;
Graphics screenCaptureGraphics;
private static int recurseCount = 0;
private static float $scale = 0.9f;
private static float scale = 1.0f;
private static int height;
private static int width;
ScreenCapture() {
try {
screenCapture = new Robot().createScreenCapture(
new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()) );
height = screenCapture.getHeight();
width = screenCapture.getWidth();
setSize(new Dimension(width, height));
addWindowListener(new LocalWindowListener());
Graphics g = recursiveDraw(screenCapture, getGraphics());
paint(g);
} catch (HeadlessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private Graphics recursiveDraw(BufferedImage img, Graphics imgG) {
updateScale(++recurseCount);
float newWidth = scale*width;
float newHeight = scale*height;
int w = (int) newWidth;
int h = (int) newHeight;
System.out.println("W: " + w + "; H: " + h);
if (w >= 10 && h >= 10) {
//scale image
System.out.print("Creating scaled Image...");
Image scaled = img.getScaledInstance(w, h, Image.SCALE_SMOOTH);
BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
imgG = resized.createGraphics();
imgG.drawImage(scaled, 0, 0, null);
System.out.println("...Image drawn to graphics");
//return new graphics
return recursiveDraw(resized, imgG);
} else {
//otherwise return old graphics
System.out.println("Completed.");
return imgG;
}
}
private void updateScale(int count) {
for (int i=0; i<count; i++) {
scale *= $scale;
}
System.out.println("Updated scale: " + scale + "; Recurse count: " + recurseCount);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ScreenCapture().setVisible(true);
}
});
}
private class LocalWindowListener extends WindowAdapter {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0); return;
}
}
}
EDIT:
This is what I tried after #andrew-thompson 's answer:
ScreenCapture() {
try {
screenCapture = new Robot().createScreenCapture(
new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()) );
height = screenCapture.getHeight();
width = screenCapture.getWidth();
setSize(new Dimension(width, height));
addWindowListener(new LocalWindowListener());
setLayout(new GridLayout());
add(new PaintPanel());
} catch (HeadlessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private class PaintPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
g=recursiveDraw(screenCapture, g);
//what to do with g?
}
}
I still have the same problem where I don't know how to make the BufferedImage paint to the graphics.
would separate out your Swing code from your recursive image creation code. In fact consider creating a static method that creates and returns the BufferedImage and that has no Swing code in it. Then have your GUI call the method when it wishes, and take the image and either write it to disk or display it in a JLabel's ImageIcon.
When I did this (today in fact), I created a recursive method with this signature
private static void recursiveDraw(BufferedImage img, Graphics imgG, double scale) {
and with this method body (in pseudo-code)
start recursiveDraw method
// most important: all recursions must have a good ending condition:
get img height and width. If either <= a min, return
create a BufferedImage, smlImg, for the smaller image using the height,
width and scale factor
Get the Graphics object, smlG, from the small image
Use smlG.drawImage(...) overload to draw the big image in shrunken
form onto the little image
recursively call recursiveDraw passing in smlImg, smlG, and scale.
dispose of smlG
draw smlImg (the small image) onto the bigger one using the bigger's
Graphics object (passed into this method) and a different
overload of the drawImage method.
end recursiveDraw method
This algorithm resulted in images like:
For example:
import java.awt.*;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class RecursiveDrawTest {
private static final Color BACKGRND_1 = Color.green;
private static final Color BACKGRND_2 = Color.MAGENTA;
private static final Color FOREGRND_1 = Color.blue;
private static final Color FOREGRND_2 = Color.RED;
private static void createAndShowGui() {
final JPanel mainPanel = new JPanel(new BorderLayout());
final JSlider slider = new JSlider(50, 90, 65);
slider.setMajorTickSpacing(10);
slider.setMinorTickSpacing(5);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
JPanel southPanel = new JPanel();
southPanel.add(new JLabel("Percent Size Reduction:"));
southPanel.add(slider);
southPanel.add(new JButton(new AbstractAction("Create Recursive Image") {
#Override
public void actionPerformed(ActionEvent arg0) {
try {
double scale = slider.getValue() / 100.0;
BufferedImage img = createRecursiveImg(scale);
ImageIcon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
Window win = SwingUtilities.getWindowAncestor(mainPanel);
JDialog dialog = new JDialog(win, "Image", ModalityType.MODELESS);
dialog.getContentPane().add(label);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
} catch (AWTException e) {
e.printStackTrace();
}
}
}));
mainPanel.add(new JScrollPane(new JLabel(new ImageIcon(createLabelImg()))),
BorderLayout.CENTER);
mainPanel.add(southPanel, BorderLayout.PAGE_END);
JFrame frame = new JFrame("RecursiveDrawTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
// create a background image to display in a JLabel so that the GUI
// won't be boring.
private static BufferedImage createLabelImg() {
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int width = (5 * d.width) / 6;
int height = (5 * d.height) / 6;
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(new GradientPaint(0, 0, BACKGRND_1, 40, 40, BACKGRND_2, true));
g2.fillRect(0, 0, width, height);
g2.setPaint(new GradientPaint(0, height, FOREGRND_1, 40, height - 40, FOREGRND_2, true));
g2.fillOval(0, 0, 2 * width, 2 * height);
g2.dispose();
return img;
}
// non-recursive image to get the initial image that will be drawn recursively
public static BufferedImage createRecursiveImg(double scale) throws AWTException {
Robot robot = new Robot();
Dimension screenSz = Toolkit.getDefaultToolkit().getScreenSize();
Rectangle screenRect = new Rectangle(screenSz);
BufferedImage img = robot.createScreenCapture(screenRect);
Graphics g = img.getGraphics();
recursiveDraw(img, g, scale); // call recursive method
g.dispose();
return img;
}
// recursive method to draw image inside of image
private static void recursiveDraw(BufferedImage img, Graphics g, double scale) {
int w = img.getWidth();
int h = img.getHeight();
int smlW = (int)(w * scale);
int smlH = (int)(h * scale);
// criteria to end recursion
if (smlW <= 1 || smlH <= 1) {
return;
}
BufferedImage smlImg = new BufferedImage(smlW, smlH, BufferedImage.TYPE_INT_ARGB);
Graphics smlG = smlImg.getGraphics();
// draw big image in little image, scaled to little image
smlG.drawImage(img, 0, 0, smlW, smlH, null);
// recursive call
recursiveDraw(smlImg, smlG, scale);
smlG.dispose(); // clear resources when done with them
// these guys center the smaller img on the bigger
int smlX = (w - smlW) / 2;
int smlY = (h - smlH) / 2;
// draw small img on big img
g.drawImage(smlImg, smlX, smlY, smlW, smlH, null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Graphics g = recursiveDraw(screenCapture, getGraphics());
Don't call getGraphics(). Override paint(Graphics)1 & use the supplied Graphics instance.
When using Swing, it is actually best to override the paintComponent(Graphics) method of a JComponent or JPanel. Then add that to the top-level container.
Is this what you are hoping for :
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;
public class CaptureScreen extends JPanel
{
private BufferedImage screenShot;
private JLabel imageLabel;
private BufferedImage secondScreenShot;
public void createAndDisplayGUI()
{
JFrame frame = new JFrame("CAPTURE SCREEN");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
//imageLabel = new JLabel();
//getImageForLabel();
//add(imageLabel);
frame.getContentPane().add(this);
frame.setSize(600, 600);
frame.setVisible(true);
}
private void getImageForLabel()
{
Robot robot = null;
try
{
robot = new Robot();
}
catch(Exception e)
{
e.printStackTrace();
}
screenShot = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ImageIcon icon = new ImageIcon(screenShot);
imageLabel.setIcon(icon);
}
public void paintComponent(Graphics g)
{
Robot robot = null;
try
{
robot = new Robot();
}
catch(Exception e)
{
e.printStackTrace();
}
screenShot = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
secondScreenShot = getScaledImage((Image) screenShot, 300, 300);
g.drawImage(screenShot, 0, 0, null);
g.drawImage(secondScreenShot, 150, 150, null);
}
private BufferedImage getScaledImage(Image srcImg, int w, int h)
{
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TRANSLUCENT);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, w, h, null);
g2.dispose();
return resizedImg;
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new CaptureScreen().createAndDisplayGUI();
}
});
}
}
Here is the output :
Get rid of the recursion. Create a single buffered image of the correct size and create a Graphics object for it. Just use a loop to draw progressively smaller scaled images down to whatever threshold you choose. Finally use g.drawImage() inside paintComponent() to draw your image to the screen. If you keep the recursion you need to pass the image and continually overlay the scaled down image. You do not need to return anything from the method.

Categories

Resources