Using Graphics2D to Manipulate an Image Multiple Times - java

I am trying to figure out how to take an image and use Graphics2D to manipulate it, all while being able to do multiple operations on the same image (so darkening it twice would make it darker than doing it once). Every single example I have found, is meant to manipulate an image once and display it. I need to be able to display the image multiple times. For example, let's say I have a menu with options 1, 2, 3, etc., and 1 darkens it, 2 lightens it and 3 displays the image.
How would I achieve this? I can get the image, darken it, rotate it and display it, but not with a menu or some other way of the user choosing when and what. If someone could link me to a webpage that does just that, or write a short (shorter is better), one class program to do what I described, I should be able to get going.
Basically, I need to be able to do something like this:
initialize image;
display(image);
lighten(image);
What I don't understand, is how I manipulate the image with the Graphics2D, and have it apply to my image.
This is what I have so far(mostly from here):
import java.awt.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class ShowImage extends JPanel {
Image img;
public ShowImage() {
super();
img = Toolkit.getDefaultToolkit().getImage("image.png");
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.translate(170, 0);
g2d.rotate(1);
g2d.drawImage(img, 0, 0, this);
}
public static void main(String arg[]) {
JFrame frame = new JFrame("Image Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
ShowImage panel = new ShowImage();
frame.setContentPane(panel);
frame.setVisible(true);
}
}
Currently, I am doing all the manipulation in paintComponent(), so it's not at all easy to manipulate. Is there a way to get the Graphics2D variable set up in the main, then get it into the paintComponent() somehow? I am completely lost as to how I would go about doing this.
I tried to post the links to all the webpages I viewed, but it won't let me post more than two links, because I am new.

If you need to manipulate an image in memory, create a BufferedImage and then call BufferedImage.createGraphics() to get access to a graphics object for drawing into the image's buffer.
When you want to render that image onto a component in the UI, use the paintComponent() method of that component as you have done. Note that this involves two separate graphics objects, used for two different purposes.

Related

Override paint(graphics g) Java

I have a little issue with my GUI in NetBeans. I draw images (dots) when a user clics in a JPanel at the mouse clic location. This part works just fine. I store each image locations in two different ArrayList that contains the X location and Y location. Now what I want to do is to delete the latest image drawn in the Panel after a button is clicked. So what I did is remove the last index of both ArrayList, and then call repaint() to draw all the images from the locations in both X and Y ArrayList (code below).
What is weird is that I need to resize the GUI (put it in full screen or just change its' size) in order for the drawn images to show up again in the JPanel otherwise, the panel remains empty.
Here's the parts of code that are affected :
public void paint(Graphics g) {
super.paint(g);
for(int i=0;i<=listePointsX.size()-1;i++) {
try{
BufferedImage icon = ImageIO.read(getClass().getResourceAsStream("/myimage.png"));
Graphics graphe = jPanel1.getGraphics();
graphe.setColor(Color.BLACK);
graphe.drawImage(icon, this.listePointsX.get(i),this.listePointsY.get(i), rootPane);
}catch(Exception e1){
}
}
private void jButtonUndoActionPerformed(java.awt.event.ActionEvent evt) {
if(listePointsX.size()>0){
int lastObject= listePointsX.size();
listePointsX.remove(lastObject-1);
listePointsY.remove(lastObject-1);
jPanel1.repaint();
}
else{
}
}
Any idea what I need to do to some kind of "refresh" the whole thing? Am I doing something wrong? Tried searching about that but did not find anyting...
Graphics graphe = jPanel1.getGraphics(); is NOT how painting should work, instead, you should have overriden the panel's paintComponent method and painted the points within in.
See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing
Instead, your panel should be doing ALL the work, managing the points in the ArrayList and painting them. You parent component "might" have the ability to add or remove points if that meets your design requirements, but the core responsibility remains with the panel.
Avoid performing any long running or block operations within the paint methods, they should run as fast as possible. Since the image never changes, you should simply load once (either when the class is constructed or when you first need the image) and keep using the same reference.
Alright it worked just fine now. I had to do it the way you told me up here. I created a new class that extends jPanel (below). Then in my main Form, had to create an object of this class. Whenever a user makes a click, it will call this Drawing class object and add an item to the ArrayList (this object manages everything regarding created points... It looks like this :
public class MyDrawingClass extends JPanel {
ArrayList<Integer> arrayListPointX = new ArrayList<>();
ArrayList<Integer> arrayListPointY = new ArrayList<>();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
try{
BufferedImage icon = ImageIO.read(getClass().getResourceAsStream("/images/dot.png"));
g.setColor(Color.BLACK);
if(arrayListPointX.size()<=0){
...
}
else{
for(int i=0;i<listePointsX.size();i++){
g.setColor(Color.BLACK);
g.drawImage(icon, listePointsX.get(i), listePointsY.get(i), rootPane);
}
}
}catch(Exception e){
...
}
}
So if I want to "undo", let's say my object of "MyDrawingClass" is called "draw". I can do : draw.arrayListPointX.remove(draw.arrayListPointX.size()-1); and call repaint(); to display remaining points.
Thanks for your tips appreciate it ! :)

Background image for a jPanel not working

I am new to making GUIs so I decided to try the the windows builder for eclipse, and while great I do have some doubts. I have been searching but I cannot seen to find a good way to add a background image to my "menu". For example I tried this:
public Menu() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(50, 50, 300, 250); //Dimensiones
contentPane = new JPanel() { //Imagen de Fondo
public void paintComponent(Graphics g) {
Image img = Toolkit.getDefaultToolkit().getImage(
Menu.class.getResource("/imgs/rotom.jpg"));
g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
}
};
And adding the following classes:
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
But to no avail the window remains with its dull grey color, so far my code is just the standard one WindowsBuilder cooks for you plus 4 buttons but I doubt they're of importance here. Shouldn't the code I added override the paintComponent() method of the jPanel and draw the image in it?
The class for the menu is in a package within my project and the image is within a imgs package is within the same project as well.
Thanks a lot in advance.
A simple method, if you're not interested in resizing the background image or applying any effects is to use a JLabel...
BufferedImage bg = ImageIO.read(Menu.class.getResource("/imgs/rotom.jpg"));
JLabel label = new JLabel(new ImageIcon(bg));
setContentPane(label);
setLayout(...);
There are limitations to this approach (beyond scaling), in that the preferred size of the label will always be that of the image and never take into account it's content. This is both good and bad.
The other approach, which you seem to be using, is to use a specialised component
public class BackgroundPane extends JPanel {
private BufferedImage img;
public BackgroundPane(BufferedImage img) {
this.img = img;
}
#Override
public Dimension getPreferredSize() {
return img == null ? super.getPreferredSize() : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, this);
}
}
You should avoid trying to perform any task in the paintComponent method which may take time to complete as paintComponent may be called often and usually in quick succession....
Getting the image to scale when the component is resized is an entire question into of it self, for some ideas, you could take a look at...
Java: maintaining aspect ratio of JPanel background image
Java: JPanel background not scaling
Quality of Image after resize very low -- Java
Reading/Loading images
Oh, and, you should avoid extending directly from top level containers, like JFrame, they reduce the reusability for your components and lock you into a single container

Overlay images Java

I'm trying to overlay a background picture with a .png sample, and I don't know how it works.
I tried to create 2 JPanels, but didn't find out how to overlay them, then I tried to create 2 JLabels and once again, they just stay separated.
Have you any idea ?
Thanks !
You can use one jPanel.Override paint or paintComponent method and draw your picture with graphic object.
public class MyCustomPanel extends JPanel{
private Image img;
public MyCustomPanel(// use constructor to get img or load it directly from below){
//load image
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// Draws the img to the BackgroundPanel.
g.drawImage(img, 0, 0, this);
}
}
Then you can go to your main class and use this JPanel
MyCustomPanel mcp=new MyCustomPanel(//img path);
mcp.add(new JLabel("Hello"),BorderLayout.CENTER);
add(mcp),BorderLayout.CENTER);
//etc
I hope you understand
Next time post some code if you want to have answr faster and more complex/better suited for your case.

Why is paintComponent() run even though no one calls it?

I was wondering if someone could explain how/why paintComponent() is called right after all the statements in main() are run. The reason I am confused is that there is no explicit call to painComponent() but it is run regardless.
// JComponent is a base class for custom components
public class SimpleDraw extends JPanel {
public static void main(String[] args) {
SimpleDraw canvas = new SimpleDraw();
JFrame f = new JFrame("SimpleDraw"); // jframe is the app window
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(400, 400); // window size
f.setContentPane(canvas); // add canvas to jframe
f.setVisible(true); // show the window
}
// custom graphics drawing
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g; // cast to get 2D drawing methods
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, // antialiasing look nicer
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(32)); // 32 pixel thick stroke
g2.setColor(Color.BLUE); // make it blue
g2.drawLine(0, 0, getWidth(), getHeight()); // draw line
g2.setColor(Color.RED);
g2.drawLine(getWidth(), 0, 0, getHeight());
}
}
Here is a decent little write-up on how paintComponent is handled.
Excerpt:
Who calls paintComponent
... This method is called because the user did
something with the user interface that required redrawing, or your
code has explicitly requested that it be redrawn. Called automatically
when it becomes visible When a window becomes visible (uncovered or
deminimized) or is resized, the "system" automatically calls the
paintComponent() method for all areas of the screen that have to be
redrawn. Called indirectly from a user-defined listener via repaint() ...
There's more in the write-up as well as some reference links, which, unfortunatelly, are all broken.
I also found this blog post which discusses painting/drawing in Java from a very basic point of view. Check out the first paragraph:
Why do we put all our graphical drawing code into a paintComponent()
method? It seems odd, since it would seem we should be able to simply
stick some simple graphics commands into our main() method in a Java
application and just get the drawing done. Where does paintComponent
come from? If we never call it in our code, how does it get executed?
In the Java docs you actually have to read up on paint to start getting an idea of what going on. The paintComponent documentation is not very helpful.

Getting started with Drawing and the 2D API

I'm trying to integrate some drawing functionality into my program.
I have a JLabel that has an image set on it.
I want to write a method to return my image:
public Graphics getImage(){
Graphics g = currentImage;
return g
}
But I don't know how to convert it from a JLabel to a graphics object. Then as a simple test I want to draw a line on this image:
public void paint(Graphics g) {
g.drawLine(20, 500, 700, 600);
}
Some help with getting started on this would be great.
Override paintComponent(Graphics g) method of JLabel and place all the drawing code there.
I have a JLabel that has an image set on it.
Create a copy of the image (BufferedImage image2..) and put image2 in the label.
When you need to draw, call image2.getGraphics() for a Graphics object, or image2.createGraphics() for a Graphics2D object.
See this answer for examples of creating and using images.

Categories