Java graphics programming draw image error - java

Hello I'm getting an error drawing an image onto my frame. I'm not sure what's going wrong here.
Im getting the following error here.
Java: 77: cannot find symbol
symbol: variable image
location: class DrawComponent
g.drawImage(image, 0, 0, null);
class DrawComponent extends JComponent {
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// draw a circle with the same center
double centerX = 250;
double centerY = 180;
double radius = 20;
Ellipse2D circle = new Ellipse2D.Double();
circle.setFrameFromCenter(centerX, centerY, centerX + radius, centerY + radius);
g2.setPaint(Color.RED);
g2.fill(circle);
g2.draw(circle);
String filename = "SydneyOperaHouse.jpeg";
try{
Image image = ImageIO.read(new File(filename));
}catch(IOException ex){
// Handle Exeption
}
g.drawImage(image, 0, 0, null);
}
}
Any help would be great :)

A few points.
To address the problem of the attribute scope. The image attribute should be handed to (or loaded in) the constructor and stored as a class attribute that is visible to the paint method. Never try load images (or do other potentially long running tasks) in this method.
An image for BG will typically be an embedded resource by the time of deployment, so access it by URL.
A JComponent is an ImageObserver so g.drawImage(image, 0, 0, null); should be
g.drawImage(image, 0, 0, this);
I suspect the image drawing at 0x0 should precede (be done before) drawing the red ellipse, or it will draw over the top of it.
Here is an example based on an image of Sydney (no, not the bloody opera house - fussy, fussy..).
import java.awt.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.net.URL;
public class DrawComponent extends JComponent {
private Image image;
DrawComponent(Image image) {
this.image = image;
Dimension d = new Dimension(image.getWidth(this),image.getHeight(this));
this.setPreferredSize(d);
}
public void paintComponent(Graphics g) {
// always call super first, to get borders etc.
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// paint the BG
g.drawImage(image, 0, 0, this);
// draw a circle with the same center
double centerX = 250;
double centerY = 180;
double radius = 20;
Ellipse2D circle = new Ellipse2D.Double();
circle.setFrameFromCenter(centerX, centerY, centerX + radius, centerY + radius);
g2.setPaint(Color.RED);
g2.fill(circle);
g2.draw(circle);
}
public static void main(String[] args) throws Exception {
String s = "http://pscode.org/media/citymorn1.jpg";
final Image image = ImageIO.read(new URL(s));
Runnable r = new Runnable() {
#Override
public void run() {
JComponent gui = new DrawComponent(image);
JOptionPane.showMessageDialog(null, gui);
}
};
SwingUtilities.invokeLater(r);
}
}

You simply declare your image variable in the try block... It is not visible outside it.

try{
Image image = ImageIO.read(new File(filename));
}catch(IOException ex){
// Handle Exeption
}
g.drawImage(image, 0, 0, null);
The scope of the variable image is wrong. Note that you are declaring the variable inside the try-block. The variable doesn't exist outside of the { ... } of the try-block.
Declare the variable outside the try-block:
Image image = null;
try {
image = ImageIO.read(new File(filename));
} catch(IOException ex) {
// Handle Exeption
}
if (image != null) {
g.drawImage(image, 0, 0, null);
}
By the way, you should not be doing I/O inside the paintComponent method. It's better to load the image somewhere else (when the application starts up, for example), store it in a member variable, and use it inside the paintComponent method.
When you load the image in the paintComponent method, it's going to load it every time the component needs to be painted. This will make your application slow.

What would you expect here in the case of an exception ?
String filename = "SydneyOperaHouse.jpeg";
try{
Image image = ImageIO.read(new File(filename));
}catch(IOException ex){
// Handle Exeption
}
g.drawImage(image, 0, 0, null);
You should declare/initalise and draw within the try{} block.

Related

Creating smooth edges on a BufferedImage while using Graphics2D in java

I created the following code example to demonstrate my problem. I want to draw into a BufferedImage by a Graphics2D object, but the edges are not sharp. I tried using different renderinghints, but it didn't help. I also tried a BufferedImageOp as you can see in the code, but I don't understand its meaning in drawImage and don't know its possibilites. Can you help me please?
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
public class SmoothGraphics extends JComponent{
private BufferedImage image;
private static JFrame frame;
private int x = 100;
private int y = 100;
private int size = 200;
public static void main(String[] args){
frame = new JFrame();
SmoothGraphics component = new SmoothGraphics();
frame.add(component);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
public SmoothGraphics(){
super();
setPreferredSize(new Dimension(400,400));
setBounds(100,100,400,400);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
GraphicsConfiguration gc = frame.getGraphicsConfiguration();
image = gc.createCompatibleImage(width, height);
Graphics2D imageGraphics = (Graphics2D) image.createGraphics();
imageGraphics.setColor(Color.RED);
/*imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);*/
drawExample(imageGraphics);
imageGraphics.dispose();
/*the following kernel helps with the smoothness of the rectangle, but not of the circle
int kernelWidth = 3;
int kernelHeight = 3;
float[] data = new float[kernelWidth*kernelHeight];
data[4]=1;
Kernel kernel = new Kernel(kernelWidth, kernelHeight, data);
BufferedImageOp op = new ConvolveOp(kernel);
*/
//draw image
BufferedImageOp op = null;
g2d.drawImage(image,op,0,0);
//I don't know if this line is necessary
image.flush();
}
private void drawExample(Graphics2D g2d){
//Square as path
Path2D.Double path = new Path2D.Double();
path.moveTo(x,y);
path.lineTo(x+size,y);
path.lineTo(x+size,y+size);
path.lineTo(x,y+size);
path.closePath();
g2d.draw(path);
//Circle
g2d.fillOval(x+size/4,y+size/4,size/2,size/2);
}
}
The output of my code. Notice that the edges are not very clean/sharp!
My result with antialiasing and kernel usage:
My wished result:
Okay... I believe the real problem you are facing is initial scaling of the component graphics (g), which makes your image stretched during drawImage(...). I don't get the same problem here.
To get proper smooth (or "sharp" as you call it) rendering, you do want to enable antialiasing. But you also need to paint without pixel scaling (it's possible with image too, by creating a larger image, however, I don't see why you need the extra image in this case).
Here's your sample program rewritten:
import javax.swing.*;
import java.awt.*;
public class SmoothGraphics extends JComponent {
private final int x = 100;
private final int y = 100;
private final int size = 200;
public static void main(String[] args) {
JFrame frame = new JFrame("Smooth");
SmoothGraphics component = new SmoothGraphics();
frame.getContentPane().add(component, BorderLayout.CENTER); // Add to content pane
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack(); // Pack *before* setVisible(true)!
frame.setLocationRelativeTo(null); // Center the frame after pack()
frame.setVisible(true);
}
public SmoothGraphics() {
setOpaque(true); // Minor optimization
setPreferredSize(new Dimension(400, 400)); // No need to use setBounds, pack() will fix that for you
}
#Override
public void paintComponent(Graphics g) {
// No need to call super, as we repaint everything
Graphics2D g2d = (Graphics2D) g;
// Clear background to black
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, getWidth(), getHeight());
// Paint in read, with antialiasing
g2d.setColor(Color.RED);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
drawExample(g2d);
}
private void drawExample(Graphics2D g2d) {
// Square (this way avoids the odd skewed lines)
g2d.drawRect(x, y, size, size);
// Circle
g2d.fillOval(x + size / 4, y + size / 4, size / 2, size / 2);
}
}
Result:
If you really want/need the BufferedImage, I found a way that works for me (MacOS). It might need some minor tweaks to work perfectly on other platforms.
#Override
public void paintComponent(Graphics g) {
// No need to call super, as we repaint everything
Graphics2D g2d = (Graphics2D) g;
GraphicsConfiguration gc = g2d.getDeviceConfiguration();
AffineTransform transform = gc.getNormalizingTransform();
BufferedImage image = gc.createCompatibleImage((int) ceil(getWidth() * transform.getScaleX()), (int) ceil(getHeight() * transform.getScaleY()));
Graphics2D graphics = image.createGraphics();
try {
graphics.setTransform(transform);
graphics.setColor(Color.RED);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Need antialiasing on
drawExample(graphics);
}
finally {
graphics.dispose();
}
try {
AffineTransform originalTransform = g2d.getTransform();
originalTransform.concatenate(transform.createInverse());
g2d.setTransform(originalTransform);
}
catch (NoninvertibleTransformException e) {
throw new RuntimeException(e); // API oddity, this should have been a RuntimeException
}
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // Need render QUALITY here, to avoid the stretching/tearing
// g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); // Don't need this on MacOS, but may be needed on other platforms
g2d.drawImage(image, null, 0, 0);
}
Result:

What causes poor image quality in Java JLabel icons?

Java JLabel icons are displaying with distorted pixels in JFrame. This is happening consistently with different png images (all 32x32). I am not scaling the images, they are displayed in the program 32x32, which I verified using getWidth and getHeight on the JLabel. The distortions appear in the same place each time the program is run, not randomly.
Screenshot using the example code provided below.
In this screenshot you can see an array of JLabel icons, each affected one differently.
When resizing the window from sideways, as the icon moves with the window, the distortions move across the icon like a vertical line.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
public class FrameApp extends JFrame
{
public static void main(String[] args) throws IOException
{
FrameApp frameApp = new FrameApp();
}
private FrameApp() throws IOException
{
BufferedImage image;
URL url = new URL("http://i.stack.imgur.com/L5DGx.png");
image = ImageIO.read(url);
JLabel label = new JLabel(new ImageIcon(image));
add(label);
pack();
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
Edit:
I am using JDK 11.0.3, Java SE Runtime Environment build 1.8.0_202, on Windows 8.1 64-bit.
You may think you're displaying the images at 32x32 size, but your example of the tiled images says that's not so. You have a 9x2 grid of icons, which should be 288x64 pixels, but in your sample image the grid is 302x66.
If you carefully examine your tiled image, you can see that the individual tiles are being displayed 34px wide - see the magenta border that extends from 32px to 66px. (Note, some of the tiles are displayed 33px wide; it appears to be 33, 34, 34, 33, 34...)
In order to stretch the tiles to the wider width, certain columns are being doubled (red borders) and this creates the visual glitches you are seeing.
Have you tried fixing the size of the JLabel instead of allowing it to size based on its contents?
First option:
Instead of using ImageIcon, you can try to create your own icon class drawing the Image using graphics.drawImage(x,y,width,height,null) controlling rendering quality (https://docs.oracle.com/javase/tutorial/2d/advanced/quality.html)
an example would be something like this:
public class Icon32 extends ImageIcon {
public Icon32(String f) {
super(f);
BufferedImage i= new BufferedImage(32, 32,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) i.getGraphics();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(getImage(), 0, 0, 32, 32, null);
setImage(i);
}
public int getIconHeight() {
return 32;
}
public int getIconWidth() {
return 32;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.drawImage(getImage(), x, y, c);
}
}
where the method:
getImage()
is loading your image/icon...
Second option: if you are not happy with the result you can try to use this library:
https://github.com/mortennobel/java-image-scaling
it claims to provides better image scaling options than the Java runtime provides.
Answer is from this link to generate high quality image : https://componenthouse.com/2008/02/08/high-quality-image-resize-with-java/
The appropriate class from the link :
public class ImageResize {
public static void main(String[] args) {
try {
URL url = new URL("http://i.stack.imgur.com/L5DGx.png");
BufferedImage image = ImageIO.read(url);
ImageIO.write(resizeImage(image, 32, 32), "png", new File("D:/picture3.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
private static BufferedImage resize(BufferedImage image, int width, int height) {
int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(image, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
private static BufferedImage resizeImage(BufferedImage image, int width, int height) {
image = createCompatibleImage(image);
image = resize(image, 100, 100);
image = blurImage(image);
return resize(image, width, height);
}
public static BufferedImage blurImage(BufferedImage image) {
float ninth = 1.0f/9.0f;
float[] blurKernel = {
ninth, ninth, ninth,
ninth, ninth, ninth,
ninth, ninth, ninth
};
Map<RenderingHints.Key, Object> map = new HashMap<RenderingHints.Key, Object>();
map.put(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
map.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
map.put(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
RenderingHints hints = new RenderingHints(map);
BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
return op.filter(image, null);
}
private static BufferedImage createCompatibleImage(BufferedImage image) {
GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
int w = image.getWidth();
int h = image.getHeight();
BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
Graphics2D g2 = result.createGraphics();
g2.drawRenderedImage(image, null);
g2.dispose();
return result;
}
}

Display the whole image using DrawImage() after Image rotation

I am rotating and scaling the image using AffineTransform. When I display the image using Graphics2D.drawImage() the whole image does not get displayed so I am calling the AffineTransform.translate method.
Here is the code I have currently written:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Dimension dim = getPreferredSize();
int x = (getWidth() - image.getWidth(null)) / 2;
int y = (getHeight() - image.getHeight(null)) / 2;
double angle = Math.toRadians(rotateAngle);
AffineTransform identity = new AffineTransform();
identity.scale(scale, scale);
identity.translate(x,y);
AffineTransform at = new AffineTransform();
setPreferredSize(new Dimension((int)(identity.getTranslateX()+(image.getWidth(null)*scale)),(int)(identity.getTranslateY()+(image.getHeight(null)*scale))));
at.setTransform(identity);
at.rotate(angle);
g2d.transform(at);
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
}
The translate method sometimes displays the whole image and sometimes does not depending on the image size and rotating angle. Is there anyway to make sure the whole image gets displayed after a rotate.
I had a look at this previous asked question:
Java2D Image Rotation Issue
but the solution posted there gave the same problem for me.
I finally figured out a way to do this for 90 degrees, it will not work for other degrees.
void rotate90(){
if(image!=null){
int w = image.getWidth(null); //the Width of the original image
int h = image.getHeight(null);//the Height of the original image
if(w>h){
BufferedImage dimg = new BufferedImage(w, w, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g = dimg.createGraphics();
g.translate(-(w-h), 0);
g.rotate(Math.toRadians(90), w/2, w/2);
g.drawImage(image, 0, 0,null);
BufferedImage bimg = new BufferedImage(h, w, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g2 = (Graphics2D)bimg.getGraphics();
g2.drawImage(dimg,0,0,h,w,0,0,h,w,null);
dimg.flush();
dimg=null;
image = createImage(bimg.getSource());
bimg.flush();
bimg= null;
}
else{
BufferedImage dimg = new BufferedImage(h, h, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g = dimg.createGraphics();
g.translate(-(w-h), 0);
g.rotate(Math.toRadians(90), w/2, w/2);
g.drawImage(image, 0, 0,null);
BufferedImage bimg = new BufferedImage(h, w, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g2 = (Graphics2D)bimg.getGraphics();
g2.drawImage(dimg,0,0,h,w,0,0,h,w,null);
dimg.flush();
dimg=null;
image = createImage(bimg.getSource());
bimg.flush();
bimg= null;
}
}
}
void rotateClockWise(){
if(image!=null){
rotate90();
setPanelsize();
revalidate();
repaint();
}
}
sometimes displays the whole image and sometimes does not depending on the image size and rotating angle
You need to recalculate the size of the rotated image. Here is an example of how to do that:
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 Rotation
{
BufferedImage image;
JLabel label;
public Rotation(BufferedImage image)
{
this.image = image;
}
private BufferedImage getImage(double theta)
{
// Determine the size of the rotated image
double cos = Math.abs(Math.cos(theta));
double sin = Math.abs(Math.sin(theta));
double width = image.getWidth();
double height = image.getHeight();
int w = (int)(width * cos + height * sin);
int h = (int)(width * sin + height * cos);
// Rotate and paint the original image onto a BufferedImage
BufferedImage out = new BufferedImage(w, h, image.getType());
Graphics2D g2 = out.createGraphics();
g2.setPaint(UIManager.getColor("Panel.background"));
g2.fillRect(0,0,w,h);
double x = w/2;
double y = h/2;
AffineTransform at = AffineTransform.getRotateInstance(theta, x, y);
x = (w - width)/2;
y = (h - height)/2;
at.translate(x, y);
g2.drawRenderedImage(image, at);
g2.dispose();
return out;
}
private JLabel getLabel()
{
ImageIcon icon = new ImageIcon(image);
label = new JLabel(icon);
label.setHorizontalAlignment(JLabel.CENTER);
return label;
}
private JSlider getSlider()
{
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
BufferedImage bi = getImage(Math.toRadians(value));
label.setIcon(new ImageIcon(bi));
}
});
return slider;
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
String path = "mong.jpg";
ClassLoader cl = Rotation.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
Rotation r = new Rotation(bi);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(r.getLabel()));
f.getContentPane().add(r.getSlider(), "South");
f.pack();
f.setLocation(200,200);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}
Not sure how the scaling will affect this. Maybe you can just multiply the width/height by the scaling factor?

I cant view a BufferedImage image on a JPanel

I am having a problem with the code below. If I load the image directly into the JPanel I can see it. But when I try to draw it first to the BufferedImage before drawing the BufferedImage on the JPanel the image is not visible. What am I doing wrong?
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import java.awt.*;
import javax.swing.JPanel;
/**
*
* #author Duafeb
*/
public class RTester {
BufferedImage backBuffer;
Graphics2D g2;
Pane pain;
Image img;
public RTester(){
JFrame frame=new JFrame("Sprite Tester");
frame.setSize(1200, 700);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
backBuffer= new BufferedImage(1200,700,BufferedImage.TYPE_INT_RGB);
g2=backBuffer.createGraphics();
pain=new Pane();
frame.add(pain);
Toolkit tk=Toolkit.getDefaultToolkit();
img=tk.getImage(this.getClass().getResource("running.png"));
frame.setVisible(true);
}
public class Pane extends JPanel{
#Override
public void paintComponent(Graphics g){
Graphics2D g3=(Graphics2D)g;
g3.drawImage(backBuffer, 0, 0, this);
}
}
public void display(){
g2.setColor(Color.yellow);
g2.fillRect(0, 0, pain.getWidth(), pain.getHeight());
g2.drawImage(img, 0, 0, pain);
pain.repaint();
}
public static void main(String[] args){
RTester test=new RTester();
test.display();
}
}
There are a few things that don't feel right about this...
The first is, you create a Graphics context to BufferedImage, but never dispose of it. Be careful, on some systems this can prevent the contents from been rendered, but this might relate to the screen device rather than a BufferedImage
For example, if I alter you code to paint the contents directly within the paintComponent method instead of to the BufferedImage, the image will be displayed (all bit a split second after the window becomes visible).
I'm not sure what it is you're trying to achieve by using the BufferedImage, but you could achieve the same thing straight through the paintComponent method
Instead of using Toolkit.getImage, you could use ImageIO.read, which guarantees that when it returns, the image is fully loaded (or will throw an IOException if it fails) or as #Reimeus had previously suggested, using a MediaTracker to ensure that the image is properly loaded before you continue using it.
So, you have four options....
One
Use a MediaTracker to wait for the image to be loaded...
MediaTracker mt = new MediaTracker(frame);
mt.addImage(img, 1);
try {
mt.waitForAll();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
Two
Use ImageIO.read instead...
img = ImageIO.read(this.getClass().getResource("running.png"));
Three
Render output directly in the paintComponent method...
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g3 = (Graphics2D) g;
g3.setColor(Color.yellow);
g3.fillRect(0, 0, pain.getWidth(), pain.getHeight());
g3.drawImage(img, 0, 0, obsever);
}
Four
Use you own ImageObserver to ensure that when the image is updated, you re-render it to the backing buffer...
private MyImageObsever obsever;
public void display() {
if (obsever == null) {
obsever = new MyImageObsever(this);
}
g2.setColor(Color.yellow);
g2.fillRect(0, 0, pain.getWidth(), pain.getHeight());
g2.drawImage(img, 0, 0, obsever);
pain.repaint();
}
public class MyImageObsever implements ImageObserver {
private RTester tester;
public MyImageObsever(RTester tester) {
this.tester = tester;
}
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
tester.display();
return (infoflags & (ALLBITS|ABORT)) == 0;
}
}

Save drawing on Jpanel as image

I am developing a drawing program using java socket. Multiple users can draw and save it as jpeg. Currently my save image function only save a blank canvas. It cannot save the co-ordinates drawn.
I am sharing part of my code below. =)
I did not use paint or paintComponent for my Canvas class because of the use java socket i am experiencing sending coordinate errors. Instead i am using massDraw().
class Canvas extends JPanel {
private int x, y;
private float x2, y2;
public Canvas() {
super();
this.setBackground(Color.white);
}
public void massDraw(int px, int py, int x, int y, int red, int green,
int blue, int size) {
Graphics g = canvas.getGraphics();
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHints(myBrush);
g2d.setStroke(new BasicStroke(size, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_BEVEL));
g2d.setColor(new Color(red, green, blue));
g.drawLine(px, py, x, y);
}
}// end Canvas class
SaveJpegOP class
class saveJpegOP implements ActionListener {
public void actionPerformed(ActionEvent e) {
// Ask for file name
String str = JOptionPane
.showInputDialog(null, "Enter File Name : ");
// save as jpeg
BufferedImage bufImage = new BufferedImage(canvas.getSize().width, canvas.getSize().height,BufferedImage.TYPE_INT_RGB);
canvas.paint(bufImage.createGraphics());
try {
ImageIO.write(bufImage, "jpg", new File(str + ".jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Blank canvas is saved because massDraw() is never called, especially it's not called when you invoke canvas.paint(bufImage.createGraphics()) in saveJpegOP.
paint() basically redraws entire component and since you decided not to override it (or paintComponent()), drawMass() is never called and empty canvas is painted.
So you need to override paintComponent() and call massDraw() with appropriate parameters. The parameter values can be, for instance, earlier set as properties in the Canvas class.

Categories

Resources