I have managed to save a print of the JPanel to a BufferedImage with ScreenImage class,which just use the function:
Panel.paint(Graphics g)
My problem is that I need to perform the scale on the BufferedImage, so I lose quality. If I do the scale on the graphics object I don't lose quality. Here is my code so far:
private void drawReflex(){
BufferedImage firstimg = new BufferedImage(getWidth() , getHeight(), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D g1 = firstimg.createGraphics();
this.paint(g1); // this method is inside a class which extends JPanel
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.scale(3,3);
drawReflex();
g2.scale(1,1);
}
Unfortunately I don't get any scale with the above code. What am I doing wrong?
Scaling will also generate some level or artifacts, generally speaking one step scaling is bad idea and even at the simplest of solutions, you should try and perform a factor of 2 scaling operation, stepping up/down to your desired target, something which is demonstrated here, you might even consider using something like imgscalr instead
The following example provides you with the ability to scale a Graphics context from 10% up to 300% through the use of a JSlider.
I simply generates BufferedImage at the desired scaled sized (based on the current size of the component), scales the Graphics context and then uses printAll to generate a snapshot. It then saves the resulting image in the current directly using the "scale" as part of the name
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ScalingTest {
public static void main(String[] args) {
new ScalingTest();
}
public ScalingTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
ImagePane pane = new ImagePane();
JButton btn = new JButton("Scale");
JSlider slider = new JSlider(10, 300);
slider.setMinorTickSpacing(5);
slider.setMajorTickSpacing(10);
slider.setSnapToTicks(true);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
float scale = slider.getValue() / 100f;
Dimension size = pane.getSize();
System.out.println("Original = " + size);
size.width *= scale;
size.height *= scale;
System.out.println("Scaled = " + size);
BufferedImage scaled = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = scaled.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.scale(scale, scale);
pane.printAll(g2d);
g2d.dispose();
ImageIO.write(scaled, "png", new File("Scaledx" + scale + ".png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
JPanel panel = new JPanel(new GridLayout(2, 1));
panel.add(slider);
panel.add(btn);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.add(panel, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ImagePane extends JPanel {
private BufferedImage bg;
public ImagePane() {
try {
bg = ImageIO.read(new File("/Volumes/Disk02/Dropbox/MegaTokyo/issue194.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return bg == null ? new Dimension(200, 200) : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - bg.getWidth()) / 2;
int y = (getHeight() - bg.getHeight()) / 2;
g2d.drawImage(bg, x, y, this);
g2d.dispose();
}
}
}
Personally, I'd grab the shap shot at a scale of 1:1 and scaling the resulting image as I think you'll still get a better result, but that's me. You might find The Perils of Image.getScaledInstance() of interest as to why scaling a BufferedImage doesn't always return a decent result
Related
In Java, there is the Graphics2D.fillRect(x, y, width, height) function. In my program, I am looking for something similar, yet completely opposite.
I need to fill everything on the screen except this certain x, y, width, height, sort of like an anti-fillRect. Is there a built in function that I am overlooking, or can you point me in the right direction to create one?
Not required, but it would be a nice bonus if it could work with other Java 2D shapes.
There are a few ways that might be achieved, the easiest might be to use
java.awt.geom.Area which is a highly versatile Shape implementation, which allows you to add and subtract Areas from it, for example...
I've left the fill color slightly translucent to prove the point ;)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class CutExample {
public static void main(String[] args) {
new CutExample();
}
public CutExample() {
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 BufferedImage img;
public TestPane() {
try {
img = ImageIO.read(...);
} catch (IOException ex) {
Logger.getLogger(CutExample.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getWidth()) / 2;
g2d.drawImage(img, x, y, this);
Area outter = new Area(new Rectangle(0, 0, getWidth(), getHeight()));
x = (getWidth() / 2) - 100;
y = (getHeight() / 2) - 100;
Rectangle inner = new Rectangle(x, y, 200, 200);
outter.subtract(new Area(inner));
g2d.setColor(new Color(0, 0, 0, 192));
g2d.fill(outter);
}
g2d.dispose();
}
}
}
I should also mention that you can use any other Shape you want...
So Im drawing a BufferedImage 'bird' but I want to rotate it according to the angle that it is falling. I have a bird object which contains the BufferedImage and a render() method which draw it rotated.
public void render(Graphics2D g, ImageObserver io) {
double theta = Math.tan((height - pastHeight) / .875);
System.out.println(theta);
Graphics2D g2 = (Graphics2D) bird.getGraphics();
g2.drawImage(bird, 100, (int) height, null);
g2.rotate(theta);
g2.drawImage(bird, 100, (int) height, io);
}
I call this as such
bird.render(g2, ???);
in my paintcomponent method in my jcomponent.
only problem is I dont know what to use as my ImageObserver... I've tried passing in my JFrame and my JComponent but the image no longer appears when I do that... what would I pass in for the image to appear in my window and/or how else would I achieve this rotation?
Assuming that you are doing this in something that extends JComponent, you should use
bird.render(g2, this);
As JComponent implements ImageObserver
The problem with the image disappearing isn't an issue with the ImageObserver but the point around which the rotation is occurring, which I believe is the top/left corner of the Graphics context.
Try using Graphics2D#rotate(double, int, int) which will allow you to specify the origin points of the rotation (pivot point).
Don't forget to reset your translations, as they will effect everything that is painted after your supply them and may be re-used in subsequent paint cycles.
Updated with simple example
This is a basic example that demonstrates the different uses of rotate.
First, I simply used Graphics#rotate(double)
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RotateImage {
public static void main(String[] args) {
new RotateImage();
}
public RotateImage() {
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.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
private double angel = 0d;
public TestPane() {
try {
img = ImageIO.read(...);
} catch (IOException ex) {
ex.printStackTrace();
}
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
angel += 5;
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.rotate(Math.toRadians(angel));
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
}
Then I replaced g2d.rotate(Math.toRadians(angel)); with g2d.rotate(Math.toRadians(angel), getWidth() / 2, getHeight() / 2);, which used the center position of the component (or the Graphics context) as the anchor point around which the rotation would occur...
Now, because you only want to rotate your image, you're going to need to calculate the anchor point around the current position of the image's center position (assuming you want it to rotate around the middle)
I draw in my JComponent some curves, etc .. with Graphics G ( not 2D ).
Now I want to use the scroll wheel of my mouse to zoom in and out.
Any tracks ?
I heard talk about a BuferredImage ?
There are a few considerations you need to take into account...
The end result will depend on what you want to achieve. If you are drawing curves using the Graphics2D API, it might be simpler to simply scale the coordinates each time the component is rendered. You will need to make sure that any changes in the scale are reflected in the preferred size of the component itself.
You could also render the "default" output to a BufferedImage and simply use an AffineTransform to change the scaling the is used to render the result, for example.
This simple uses a BufferedImage and loads a picture from disk, but the basic concept is the same.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ZoomPane {
public static void main(String[] args) {
new ZoomPane();
}
public ZoomPane() {
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 JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
private float scale = 1;
public TestPane() {
try {
img = ImageIO.read(new File("/path/to/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseWheelListener(new MouseAdapter() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
double delta = 0.05f * e.getPreciseWheelRotation();
scale += delta;
revalidate();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(200, 200);
if (img != null) {
size.width = Math.round(img.getWidth() * scale);
size.height = Math.round(img.getHeight() * scale);
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = new AffineTransform();
at.scale(scale, scale);
g2d.drawImage(img, at, this);
g2d.dispose();
}
}
}
}
You could also scale the Graphics context passed to your paintComponent method directly.
The important thing here is to remember to reset the AffineTransform after you have completed, otherwise it will be passed to other components when they are rendered, which won't generate the expected output...
This example basically creates a copy of the Graphics context which we can manipulate and dispose of without effecting the original, making it simpler to mess with
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.event.MouseAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ZoomPane {
public static void main(String[] args) {
new ZoomPane();
}
public ZoomPane() {
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 JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private float scale = 1;
public TestPane() {
addMouseWheelListener(new MouseAdapter() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
double delta = 0.05f * e.getPreciseWheelRotation();
scale += delta;
revalidate();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(200, 200);
size.width = Math.round(size.width * scale);
size.height = Math.round(size.height * scale);
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = new AffineTransform();
at.scale(scale, scale);
g2d.setTransform(at);
g2d.setColor(Color.RED);
// This is for demonstration purposes only
// I prefer to use getWidth and getHeight
int width = 200;
int height = 200;
Path2D.Float path = new Path2D.Float();
int seg = width / 3;
path.moveTo(0, height / 2);
path.curveTo(0, 0, seg, 0, seg, height / 2);
path.curveTo(
seg, height,
seg * 2, height,
seg * 2, height / 2);
path.curveTo(
seg * 2, 0,
seg * 3, 0,
seg * 3, height / 2);
g2d.draw(path);
g2d.dispose();
}
}
}
Take a look at Transforming Shapes, Text and Images for more details
Try JFreeChart; the setMouseWheelEnabled() method, used to control zooming in ChartPanel, is illustrated in examples cited here.
I put this simple code to show you how to use mouse wheel mouving by adding a MouseWheelListener to a JPanel:
myJpanel.addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent mwe) {
jPanelMouseWheelMoved(mwe);
}
});
To implement the mouse wheel listener:
private void jPaneMouseWheelMoved(MouseWheelEvent mwe) {
if(Event.ALT_MASK != 0) {
if(mwe.getWheelRotation() > 0) {
//here you put your code to scrool douwn or to minimize.
System.out.println(" minimize by "+(-1*mwe.getWheelRotation()));
}
else if(mwe.getWheelRotation() < 0) {
//here you put your code to scrool up or to maximize.
System.out.println(" maximaze by "+(-1*mwe.getWheelRotation()));
}
}
}
You can adapt this exemple to zoom or to scrool what you want.
I'm making a 'game' of sorts where the player has to click on an image bouncing around the screen. The catch is that the screen is in darkness and the mouse cursor is a 'flashlight' which 'light up' a small circle around it.
I have a JFrame in one class consisting of:
public class GameFrame {
public static void main(String[] args) throws IOException {
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
JFrame jf = new JFrame("Flashlight Game");
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(d);
jf.setLocationRelativeTo(null);
GamePanel gp = new GamePanel();
jf.add(gp);
}
}
I have another class which extends JPanel. Here are its fields relevant to my problems:
private Point mouse; //location set by a MouseMotionListener
private BufferedImage myImage;
private int imageX;
private int imageY;
private int imageSpeedX;
private int imageSpeedY;
My first problem lies in the flashlight. In my paint method, I set the graphics background color to the panel background color and use the clearRect method to clear an area around the mouse cursor.
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paint(g2);
checkBounce();
move();
g2.drawImage(myImage, imageX, imageY, null);
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, this.getWidth(), this.getHeight());
g2.setBackground(Color.WHITE);
g2.clearRect((int) mouse.getX() - 25, (int) mouse.getY() - 25, 50, 50);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
There are actually two problems here.
1.) How can I create a clearOval effect since a flashlight doesn't shine in a rectangle, and
2.) How can I get the bouncing image to show up through the flashlight beam? I know that calling g2.setBackground(Color.WHITE) will use the set color as the 'background' for the cleared area, but I need a way to clear all graphics except for the backmost JFrame or JPanel background color.
My last problem is sorta weird, but occasionally when I change the value of an int, the window will appear as blank and needs resizing before any of the code will execute.
The basic idea is to create a Rectangle big enough to cover the component, create a Ellipse2D to act as the "hole" or "spot light" and subtract the Ellipse2D from Rectangle so as to create a hole in it, then paint it.
You should avoid overridding paint where possible and instead, use paintComponent, paint tends to be to high in the paint chain and comes with a number of complications which are best avoided
You should avoid changing the state the state of your component or model within any paintXxx method. Paint can be called for any number of reasons, many of which you won't instantiate. This could be putting your models state into a inconsistent state. Instead, you should using something like a javax.swing.Timer to regulate when the model is updated and simply call repaint
Don't ever call Thread.sleep, Threasd.wait or perform any kind of long running loop or I/O operation within the context of the Event Dispatching Thread. Swing is a single threaded environment. That is, all the updates to the UI and event processing are done from within a single thread. If you do anything that blocks the EDT, it will be unable to process these events and update the UI until you stop blocking...
Don't call repaint or any method that might invoke a repaint from within in paintXxx method. This will place your program into a spiral of death that will see it consume your CPU...
For more details, take a look at...
Performing Custom Painting
Concurrency in Swing
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.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Spotlight {
public static void main(String[] args) {
new Spotlight();
}
public Spotlight() {
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 {
public static final int RADIUS = 80;
private BufferedImage img;
private Point mousePoint;
public TestPane() {
try {
img = ImageIO.read(new File("C:\\hold\\thumbnails\\Rampage_Small.png"));
} catch (IOException ex) {
Logger.getLogger(Spotlight.class.getName()).log(Level.SEVERE, null, ex);
}
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
mousePoint = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
x = mousePoint == null ? getWidth() / 2 : mousePoint.x;
y = mousePoint == null ? getHeight() / 2 : mousePoint.y;
Rectangle rect = new Rectangle(0, 0, getWidth(), getHeight());
Ellipse2D spot = new Ellipse2D.Float(
(float) x - (RADIUS / 2f),
(float) y - (RADIUS / 2f),
(float) RADIUS,
(float) RADIUS);
Area area = new Area(rect);
area.subtract(new Area(spot));
g2d.setColor(Color.BLACK);
g2d.fill(area);
g2d.dispose();
}
}
}
}
I am using JFrame and I have kept a background image on my frame. Now the problem is that the size of image is smaller then the size of the frame so i have to keep the same image once again on the empty part of the window. If user clicks maximize button than I may have to put the image on empty region of the frame at run time. Can anyone tell me how to accomplish this?
It sounds as though you are talking about tiling vs. stretching, though it's not clear which behaviour you want.
This program has examples of both:
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) throws IOException {
final Image image = ImageIO.read(new URL("http://sstatic.net/so/img/logo.png"));
final JFrame frame = new JFrame();
frame.add(new ImagePanel(image));
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
#SuppressWarnings("serial")
class ImagePanel extends JPanel {
private Image image;
private boolean tile;
ImagePanel(Image image) {
this.image = image;
this.tile = false;
final JCheckBox checkBox = new JCheckBox();
checkBox.setAction(new AbstractAction("Tile") {
public void actionPerformed(ActionEvent e) {
tile = checkBox.isSelected();
repaint();
}
});
add(checkBox, BorderLayout.SOUTH);
};
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (tile) {
int iw = image.getWidth(this);
int ih = image.getHeight(this);
if (iw > 0 && ih > 0) {
for (int x = 0; x < getWidth(); x += iw) {
for (int y = 0; y < getHeight(); y += ih) {
g.drawImage(image, x, y, iw, ih, this);
}
}
}
} else {
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
}
}
You want something like the background image of the windows desktop, when using the background image multiple times instead of resizing it or just display it centered?
You only have to keep the image once and just paint it multiple times in the paintComponent method.
Another way to tile an image is with TexturePaint:
public class TexturePanel extends JPanel {
private TexturePaint paint;
public TexturePanel(BufferedImage bi) {
super();
this.paint = new TexturePaint(bi, new Rectangle(0, 0, bi.getWidth(), bi.getHeight()));
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(paint);
g2.fill(new Rectangle(0, 0, getWidth(), getHeight()));
}
}