is it possible to display two pictures, next to each other with BufferedImage and Graphics2D ? or should I do it with other method ?
In my code below, I was able to display two images, but the picture 1 overlaps to the picture 2.
package zdjecie;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class ObrazPanel extends JPanel {
private BufferedImage image;
private BufferedImage image2;
public ObrazPanel() {
super();
File imageFile = new File("C:\\Users\\KostrzewskiT\\eclipse-workspace\\zdjecie\\src\\zdjecie\\java.jpg");
File imageFile2 = new File("C:\\Users\\KostrzewskiT\\eclipse-workspace\\zdjecie\\src\\zdjecie\\java2.jpg");
try {
image = ImageIO.read(imageFile);
image2 = ImageIO.read(imageFile2);
} catch (IOException e) {
System.err.println("Blad odczytu obrazka");
e.printStackTrace();
}
Dimension dimension = new Dimension(image.getWidth(), image.getHeight());
setPreferredSize(dimension);
Dimension dimension2 = new Dimension(image2.getWidth(), image2.getHeight());
setPreferredSize(dimension2);
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, 0, 0, this);
g2d.drawImage(image2, 200, 200, this);
}
}
You call setPreferredSize twice, which results in the first call doing basically nothing. That means you always have a preferredSize equal to the dimensions of the second image. What you should do is to set the size to new Dimension(image.getWidth() + image2.getWidth(), image2.getHeight()) assuming both have the same height. If that is not the case set the height as the maximum of both images.
Secondly you need to offset the second image from the first image exactly by the width of the first image:
g2d.drawImage(image, 0, 0, this);
g2d.drawImage(image2, image.getWidth(), 0, this);
The logic of the math was incorrect. See the getPreferredSize() method for the correct way to calculate the required width, and the changes to the paintComponent(Graphics) method to place them side-by-side.
An alternative (not examined in this answer) is to put each image into a JLabel, then add the labels to a panel with an appropriate layout.
This is the effect of the changes:
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.net.*;
import javax.imageio.ImageIO;
public class ObrazPanel extends JPanel {
private BufferedImage image;
private BufferedImage image2;
public ObrazPanel() throws MalformedURLException {
super();
URL imageFile = new URL("https://i.stack.imgur.com/7bI1Y.jpg");
URL imageFile2 = new URL("https://i.stack.imgur.com/aH5zB.jpg");
try {
image = ImageIO.read(imageFile);
image2 = ImageIO.read(imageFile2);
} catch (Exception e) {
System.err.println("Blad odczytu obrazka");
e.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
int w = image.getWidth() + image2.getWidth();
int h1 = image.getHeight();
int h2 = image2.getHeight();
int h = h1>h2 ? h1 : h2;
return new Dimension(w,h);
}
#Override
public void paintComponent(Graphics g) {
// always best to start with this..
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, 0, 0, this);
g2d.drawImage(image2, image.getWidth(), 0, this);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
ObrazPanel o;
try {
o = new ObrazPanel();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o);
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
};
SwingUtilities.invokeLater(r);
}
}
I would join the images whenever something changes and draw them to another buffered image. Then I can just redraw the combined image whenever the panel needs to be redrawn.
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class SideBySideImagePanel extends JPanel {
private static final long serialVersionUID = 5868633578732134172L;
private BufferedImage left;
private BufferedImage right;
private BufferedImage join;
public SideBySideImagePanel() {
ClassLoader loader = this.getClass().getClassLoader();
BufferedImage left = null, right = null;
try {
left = ImageIO.read(loader.getResourceAsStream("resources/Android.png"));
right = ImageIO.read(loader.getResourceAsStream("resources/Java.png"));
} catch (IOException e) {
e.printStackTrace();
}
this.setLeft(left);
this.setRight(right);
}
public BufferedImage getLeft() {
return left;
}
public void setLeft(BufferedImage left) {
this.left = left;
}
public BufferedImage getRight() {
return right;
}
public void setRight(BufferedImage right) {
this.right = right;
}
#Override
public void invalidate() {
super.invalidate();
join = combineImages(left, right);
setPreferredSize(new Dimension(join.getWidth(), join.getHeight()));
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(join, 0, 0, null);
}
private BufferedImage combineImages(BufferedImage left, BufferedImage right) {
int width = left.getWidth() + right.getWidth();
int height = Math.max(left.getHeight(), right.getHeight());
BufferedImage combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = combined.getGraphics();
g.drawImage(left, 0, 0, null);
g.drawImage(right, left.getWidth(), 0, null);
return combined;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Image Joiner");
SideBySideImagePanel panel = new SideBySideImagePanel();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
});
}
}
I found some errors in your code and I did not got what are you trying to do...
1] Over there you are actually not using the first setup
Dimension dimension = new Dimension(image.getWidth(), image.getHeight());
setPreferredSize(dimension); //not used
Dimension dimension2 = new Dimension(image2.getWidth(), image2.getHeight());
setPreferredSize(dimension2); //because overridden by this
It means, panel is having dimensions same as the image2, you should to set it as follows:
height as max of the heights of both images
width at least as summarize of widths of both pictures (if you want to paint them in same panel, as you are trying)
2] what is the image and image2 datatypes? in the block above you have File but with different naming variables, File class ofcourse dont have width or height argument
I am assuming its Image due usage in Graphics.drawImage, then:
You need to setup preferred size as I mentioned:
height to max value of height from images
width at least as summarize value of each widths
Dimensions things:
Dimension panelDim = new Dimension(image.getWidth() + image2.getWidth(),Math.max(image.getHeight(),image2.getHeight()));
setPreferredSize(panelDim)
Then you can draw images in the original size
- due coordinates are having 0;0 in the left top corner and right bottom is this.getWidth(); this.getHeight()
- check eg. this explanation
- you need to start paint in the left bottom corner and then move to correct position increase "X" as the width of first image
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
/* public abstract boolean drawImage(Image img,
int x,
int y,
Color bgcolor,
ImageObserver observer)
*/
//start to paint at [0;0]
g2d.drawImage(image, 0, 0, this);
//start to paint just on the right side of first image (offset equals to width of first picture)- next pixel on the same line, on the bottom of the screen
g2d.drawImage(image2,image2.getWidth()+1, 0, this);
}
I didn't had a chance to test it, but it should be like this.
Important things are
you need to have proper dimensions for fitting both images
screen coordinates starts in the left top corner of the screens [0;0]
Related
I am trying to create spinning image Animation but something seems to be not working in the code. I am rotating image at various angles and drawing it but at the end I only end up single rotated image than animation. Is this possible to do in Java or do I need switch to C# Unity where I found multiple examples on doing so nothing so far in Java. I am new to Swing so I would really appreciate simplified answer.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.util.concurrent.TimeUnit;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Rotate extends JPanel {
public static void main(String[] args) {
new Rotate().go();
}
public void go() {
JFrame frame = new JFrame("Rotate");
JButton b = new JButton("click");
MyDrawPanel p = new MyDrawPanel();
frame.add(p);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1000, 1000);
frame.setVisible(true);
for(int i = 0; i < 300; i++) {
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
repaint();
}
}
class MyDrawPanel extends JPanel{
Image image = new ImageIcon(
getClass()
.getResource("wheel.png"))
.getImage();
public void animateCircle(Graphics2D g2d ) {
//g2d = (Graphics2D) g2d.create();
g2d.rotate(Math.toRadians(25), 250, 250);
g2d.drawImage(image, 0, 0, 500, 500, this);
}
#Override
protected void paintComponent(Graphics g) {
//super.paintComponent(g);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
Graphics2D g2d = (Graphics2D) g;
animateCircle(g2d);
}
}
}
I tried moving for loop in the paintComponent() method but it didn't help either.
Here
public void animateCircle(Graphics2D g2d ) {
//g2d = (Graphics2D) g2d.create();
g2d.rotate(Math.toRadians(25), 250, 250);
g2d.drawImage(image, 0, 0, 500, 500, this);
}
You rotation is fixed, so you aren't seeing your image spinning
By changing your value in Math.toRadians(...), you can make it appear to spin
This
for(int i = 0; i < 300; i++) {
rotationStep ++;
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
repaint();
}
}
Is the wrong way to do animation in swing. The right way is to use a javax.swing.Timer
public class MyTimer implements ActionListener {
int rotationStep = 0;
public void actionPerformed(ActionEvent ae) {
// for(int i = 0; i < 300; i++) {
rotationStep ++;
repaint();
}
}
You can do it like this. I reorganized some of your code which you can of course change at your leisure. Most of the critical elements are documented within the code. Major changes include:
eliminating magic numbers - allows alterations to happen in one place
using Rendering hints to eliminate rotating images.
overridding getPreferredSize() in the panel class
computing panel size to allow full rotation within panel.
using a swing timer to control repaint and angle updates
public class Rotate extends JPanel {
BufferedImage image = null;
public static void main(String[] args) {
new Rotate().go();
}
public void go() {
JFrame frame = new JFrame("Rotate");
JButton b = new JButton("click");
File file = new File("wheel.png");
try {
image = ImageIO
.read(new FileInputStream(new File("H:/Bench.jpg")));
} catch (IOException ioe) {
ioe.printStackTrace();
}
// invoke an instance of the panel with the image
MyDrawPanel p = new MyDrawPanel();
frame.add(p);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
// center the frame on the screen
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// start the animation
p.animateCircle();
}
class MyDrawPanel extends JPanel {
double angle = 0;
//increment of the angle of rotation
double inc = Math.toRadians(.1);
int imageWidth;
int imageHeight;
int panelWidth;
int panelHeight;
double ctrX;
double ctrY;
int startX;
int startY;
#Override
public Dimension getPreferredSize() {
return new Dimension(panelWidth, panelHeight);
}
public MyDrawPanel() {
double imageWidth = image.getWidth();
double imageHeight = image.getHeight();
setBackground(Color.WHITE);
// compute panel size to allow full rotation within by computing
//the image's diagonal length
panelWidth = (int)Math.hypot(imageWidth, imageHeight);
panelHeight = panelWidth;
//target location for writing object (upper left corner)
startX = (int)(panelWidth-imageWidth)/2;
startY = (int)(panelHeight-imageHeight)/2;
// center of rotation
ctrX = panelWidth/2;
ctrY = panelHeight/2;
}
// This starts the animation using a swing timer to update the angle and repaint the image
public void animateCircle() {
Timer timer = new Timer(0, (ae)-> {
angle += inc; repaint();
});
timer.setDelay(10);
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// setting the rendering hints allows smooth rotation of images with minimal distortion
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
// rotate the graphics context about the center
g2d.rotate(angle, ctrX, ctrY);
// draw the image. Top left at startX and startY
g2d.drawImage(image, startX, startY, this);
}
}
}
Note: If the timer is set to a low value (faster rotation) and the image is too large, the image may not finish the current rotation cycle before the timer re-fires.
I develop a game and rotating images currently takes most of the time in the calculation process of a frame. For optimization I'm searching for the fastest way to rotate a buffered-image. I already tried two methods shown down there.
slowest method:
public static BufferedImage rotate(BufferedImage imgOld, int deg){ //Parameter for this method are the picture to rotate and the rotation in degrees
AffineTransform at = AffineTransform.getRotateInstance(Math.toRadians(deg), (int)(imgOld.getWidth()/2), (int)(imgOld.getHeight()/2)); //initialize and configure transformation
BufferedImage imgNew = new BufferedImage(imgOld.getWidth(), imgOld.getHeight(), imgOld.getType()); //create new bufferedimage with the properties of the image to rotate
Graphics2D g = (Graphics2D) imgNew.getGraphics(); //create Graphics
g.setTransform(at); //apply transformation
g.drawImage(imgOld, 0, 0, null); //draw rotated image
g.dispose();
imgOld.flush();
return imgNew;
}
little bit faster method :
public static BufferedImage rotate(BufferedImage imgOld, int deg){ //parameter same as method above
BufferedImage imgNew = new BufferedImage(imgOld.getWidth(), imgOld.getHeight(), imgOld.getType()); //create new buffered image
Graphics2D g = (Graphics2D) imgNew.getGraphics(); //create new graphics
g.rotate(QaDMath.toRadians(deg), imgOld.getWidth()/2, imgOld.getHeight()/2); //configure rotation
g.drawImage(imgOld, 0, 0, null); //draw rotated image
return imgNew; //return rotated image
}
}
I found many topics related to rotating an image but not a single one discussing the fastest, most solution.
I hope i didn't miss any topic and this isn't a duplicate.
Hopefully there is someone more skilled than me out there knowing a solution
I would guess that part of the problem is that you are continually creating new BufferedImages to do the rotation. This results in you doing the painting twice, once when you paint onto the BufferedImage and the second time when you paint the BufferedImage on the frame.
You could try to just paint the existing BufferedImage rotated. For example you could use the Rotated Icon and then just paint the icon using
rotated.paintIcon(...);
Whenever you need to rotate the image you just use:
rotated.setDegrees(...);
Simple example:
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation3 extends JPanel
{
private Icon icon;
private RotatedIcon rotated;
private int degrees;
public Rotation3(Image image)
{
icon = new ImageIcon( image );
rotated = new RotatedIcon(icon, 0);
rotated.setCircularIcon( true );
setDegrees( 0 );
setPreferredSize( new Dimension(600, 600) );
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
double radians = Math.toRadians( degrees );
// translate x/y so Icon rotated around a specific point (300, 300)
int x = 300 - (rotated.getIconWidth() / 2);
int y = 300 - (rotated.getIconHeight() / 2);
rotated.paintIcon(this, g, x, y);
g.setColor(Color.RED);
g.fillOval(295, 295, 10, 10);
}
public void setDegrees(int degrees)
{
this.degrees = degrees;
rotated.setDegrees(degrees);
repaint();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
String path = "dukewavered.gif";
ClassLoader cl = Rotation3.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
final Rotation3 r = new Rotation3(bi);
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
r.setDegrees( value );
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(r));
f.add(slider, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}
Just drag the slider to see the rotation.
I hope my first post isn't too basic for y'all.
I'm trying to do some per-pixel drawing on a JCanvas using a BufferedImage (using setRGB()). I thought I would test all was working with a single diagonal line from the origin to the width/height of the JCanvas. The trouble is that I get a strange offset in the x axis that I can't seem to fix!
Here's a link to the problem:
http://i811.photobucket.com/albums/zz31/bohngy/problemMandel_zpsae20713a.jpeg
Here's the code:
public class Mandelbrot extends JFrame {
private BufferedImage I;
public Mandelbrot() {
super("Mandelbrot Set");
setSize(600, 600);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
I = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < getHeight(); x++) {
for (int y = 0; y < getWidth(); y++) {
I.setRGB(x, x, Color.GREEN.getRGB());
}
}
}
#Override
public void paint(Graphics g) {
g.drawImage(I, 0, 0, this);
}
public static void main(String[] args) {
new Mandelbrot().setVisible(true);
}
}
General issues
Don't extend JFrame (particularly, don't override the paint method of JFrame). Instead, do the painting in the paintComponent method a class that extends JPanel
Create the GUI from the Event Dispatch Thread
The main reason for the unexpected result is that you are creating an image that has the size of the frame - but the frame also has a title bar and a border, and these are "covering" parts of the image. The size of the area that is actually available for painting is smaller than the total frame size. Additionally, the getWidth() and getHeight() methods may return garbage as long as the frame is not yet visible on the screen.
One approach considering all this could look like in this snippet:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Mandelbrot
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(1, 1));
BufferedImage image = createImage(500, 500);
ImagePanel imagePanel = new ImagePanel(image);
frame.getContentPane().add(imagePanel);
frame.pack();
frame.setVisible(true);
}
private static BufferedImage createImage(int w, int h)
{
BufferedImage image = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < w; x++)
{
image.setRGB(x, x, Color.GREEN.getRGB());
}
return image;
}
static class ImagePanel extends JPanel
{
private final BufferedImage image;
ImagePanel(BufferedImage image)
{
this.image = image;
}
#Override
public Dimension getPreferredSize()
{
if (super.isPreferredSizeSet())
{
return super.getPreferredSize();
}
return new Dimension(image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
}
}
All BufferedImage objects have an upper left corner coordinate of (0, 0). Any Raster used to construct a BufferedImage must therefore have minX=0 and minY=0.
Therein lies your problem.
JavaDoc for BufferedImage
Edit:
Also remove this from your loop:
for (int y = 0; y < getWidth(); y++) {
I.setRGB(x, x, Color.GREEN.getRGB());
}
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 want to convert an JPanel to an image. I used the following method:
public BufferedImage createImage(){
int w = getWidth();
int h = getHeight();
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
paint(g);
return bi;
}
But the problem is that the JPanel is contained within a JScrollPane. So when I convert the jpanel to an image, the image contains only the parts visible in the jpanel and the parts that are hidden inside the scrollpane aren't contained in the image.
Are there any solutions to get the full content of the JPanel into an image?
But the problem is that the JPanel is contained within a JScrollPane.
So when I convert the jpanel to an image, the image contains only the
parts visible in the jpanel and the parts that are hidden inside the
scrollpane aren't contained in the image.
This doesnt happen to me... have you tried paintAll instead of paint?
Here is a great method which will capture the content of any Component visible or not (Its not mine I got it somewhere off the SO and have used it since):
public static BufferedImage componentToImage(Component component, boolean visible) {
if (visible) {
BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
Graphics2D g2d = (Graphics2D) img.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
component.paintAll(g2d);
return img;
} else {
component.setSize(component.getPreferredSize());
layoutComponent(component);
BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
CellRendererPane crp = new CellRendererPane();
crp.add(component);
crp.paintComponent(img.createGraphics(), component, crp, component.getBounds());
return img;
}
}
private static void layoutComponent(Component c) {
synchronized (c.getTreeLock()) {
c.doLayout();
if (c instanceof Container) {
for (Component child : ((Container) c).getComponents()) {
layoutComponent(child);
}
}
}
}
Here is an example showcasing the above:
The frame view:
capture of the panel:
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.CellRendererPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
createAndShowGui();
}
private void createAndShowGui() {
JFrame frame = new JFrame() {
#Override
public Dimension getPreferredSize() {//size frame purposefully smaller
return new Dimension(100, 100);
}
};
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Image img = null;
try {
img = ImageIO.read(new URL("http://images4.wikia.nocookie.net/__cb20120515073660/naruto/images/0/09/Naruto_newshot.png")).getScaledInstance(200, 200, Image.SCALE_SMOOTH);
} catch (Exception ex) {
ex.printStackTrace();
}
final ImagePanel imagePanel = new ImagePanel(200, 200, img);
JScrollPane jsp = new JScrollPane(imagePanel);
frame.add(jsp);
frame.pack();
frame.setVisible(true);
BufferedImage bi = componentToImage(imagePanel, true);
try {
File outputfile = new File("c:/saved.png");
ImageIO.write(bi, "png", outputfile);
} catch (IOException e) {
e.printStackTrace();
}
}
public static BufferedImage componentToImage(Component component, boolean visible) {
if (visible) {
BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
Graphics2D g2d = (Graphics2D) img.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
component.paintAll(g2d);
return img;
} else {
component.setSize(component.getPreferredSize());
layoutComponent(component);
BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
CellRendererPane crp = new CellRendererPane();
crp.add(component);
crp.paintComponent(img.createGraphics(), component, crp, component.getBounds());
return img;
}
}
private static void layoutComponent(Component c) {
synchronized (c.getTreeLock()) {
c.doLayout();
if (c instanceof Container) {
for (Component child : ((Container) c).getComponents()) {
layoutComponent(child);
}
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class ImagePanel extends JPanel {
int width, height;
Image bg;
public ImagePanel(int width, int height, Image bg) {
this.width = width;
this.height = height;
this.bg = bg;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
grphcs.drawImage(bg, 0, 0, null);
}
}
UPDATE:
As per your comment:
I wrote the BufferedImage into a file by using
ImageIO.write(bufferedImage, "jpg" , file); this works fine for both
png and gif images, but jpg image shows a red background instead of
white. How can i slove that problem. Thanks
See this similar question/answer for more. You would do something like:
private static final int[] RGB_MASKS = {0xFF0000, 0xFF00, 0xFF};
private static final ColorModel RGB_OPAQUE = new DirectColorModel(32, RGB_MASKS[0], RGB_MASKS[1], RGB_MASKS[2]);
...
BufferedImage image = componentToImage(imagePanel, true);
saveJPeg(image, "c:/saved.jpg");
private void saveJPeg(BufferedImage image, String name) {
PixelGrabber pg = new PixelGrabber(image, 0, 0, -1, -1, true);
try {
pg.grabPixels();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
int width = pg.getWidth(), height = pg.getHeight();
DataBuffer buffer = new DataBufferInt((int[]) pg.getPixels(), pg.getWidth() * pg.getHeight());
WritableRaster raster = Raster.createPackedRaster(buffer, width, height, width, RGB_MASKS, null);
BufferedImage bi = new BufferedImage(RGB_OPAQUE, raster, false, null);
try {
ImageIO.write(bi, "jpg", new File(name));
} catch (IOException ex) {
ex.printStackTrace();
}
}
SwingUtilities.paintComponent does it:
static void drawComponent(JComponent c,
BufferedImage destination) {
JFrame frame = new JFrame();
Graphics g = destination.createGraphics();
SwingUtilities.paintComponent(g, c, frame.getContentPane(),
0, 0, destination.getWidth(), destination.getHeight());
g.dispose();
frame.dispose();
}
static BufferedImage createSnapshotOf(JComponent c) {
Dimension size = c.getSize();
if (size.width <= 0 || size.height <= 0) {
size = c.getPreferredSize();
}
BufferedImage snapshot =
new BufferedImage(size.width, size.height,
BufferedImage.TYPE_INT_ARGB);
drawComponent(c, snapshot);
return snapshot;
}
I don't know why you need to do something so complicated. As long as your Buffered image and paint function all use the component (huge) that is the in the JScroolPane, the whole thing should be saved.
//create a tree data structure
DefaultMutableTreeNode tree = new DefaultMutableTreeNode("root");
//optional: you can make the tree really big
//now show the tree
JFrame frame = new JFrame("TreeDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create a Jtree component to display your data structure
JTree treeDisplay = new JTree(tree);
//expand the tree all out
for(int i = 0; i < treeDisplay.getRowCount(); i++) {
treeDisplay.expandRow(i);
}
//put your tree display component in a scroll pane
frame.add(new JScrollPane(treeDisplay));
//Display the window.
frame.pack();
frame.setVisible(true);
//save tree in the window to a file
BufferedImage img = new BufferedImage(treeDisplay.getWidth(), treeDisplay.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
//put graphics on the buffered image
treeDisplay.paintAll(graphics);
graphics.dispose();
try {
ImageIO.write(img, "png", new File("tree.png"));
}
catch (IOException e) {
e.printStackTrace();
}