I have a PNG image with transparency. I used the format because only PNG can support transparency and alpha masks.
My aim is to paint a JPanel with this image and let the transparent regions have the color of the underlying panel, And ultimately do some animations with the image.
How ever I am facing problems, the transparent regions turn out to be solid white color when loaded and painted on the JPanel.
So java does not support transparent images?
class imgpanel extends JPanel{
BufferedImage image,backg;
imgpanel(){
try {
image = ImageIO.read(new File("theimage.png"));
backg = ImageIO.read(new File("backimage.png"));
} catch (IOException ex) {
System.out.println("No image found");
}
setPreferredSize(new Dimension(400,300));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(backg,0,0,null);
g.drawImage(image, 0, 0, null);
}
}
Thus I am painting the transparent "theimage" onto the opaque "backimage"
Yes no problem, do not use palettes, indexed colors.
Try out, whether the images really are transparent, have an alpha component in the color.
For instance with a test.html:
<html>
<body>
<div style="background: url(backimage.png)"><img src="theimage.png"></div>
</body>
</html>
From my experience ImageIO.read loads the image without the transparency by picking wrong transparency/image type. Therefore I use a workaround - ImageIcon to load it as an Image, which can be drawn into empty BufferedImage with predefined image type BufferedImage.TYPE_INT_ARGB. And don't forget ImageIcon forbids the garbage collector to collect the Image, if the image is not flushed afterwards.
ImageIcon imageIcon = new ImageIcon(imageAbsolutePath);
Image tmpImage = imageIcon.getImage();
BufferedImage image = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
image.getGraphics().drawImage(tmpImage, 0, 0, null);
tmpImage.flush();
return image;
Related
I am writing a program that consists of three different panels.
This is part of my bottom panel. I display an image using BufferedImage, and I would like to create some text that will appear around 350px into the image, and 15px down. I cannot manage to get this to work and overlay over the bufferedImage.
My current code is as follows (For the bottom panel):
public class BtmPanel extends JPanel {
BtmPanel(){
try {
JLabel imgLabel = new JLabel();
final BufferedImage img = ImageIO.read(new File("image.png"));
ImageIcon icon = new ImageIcon(img);
imgLabel.setIcon(icon);
this.add(imgLabel);
}
catch(IOException ie){
System.out.println("image does not exist");
}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("Y: " + MiddlePanel.y ,350,15);
}
}
There are a couple of ways you might achieve this, depending on your needs and desires.
For example, rather than using a JLabel to display the image, you could paint it directly yourself, for example...
public class BtmPanel extends JPanel {
private BufferedImage image;
BtmPanel(){
try {
image = ImageIO.read(new File("image.png"));
}
catch(IOException ie){
System.out.println("image does not exist");
}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(0, 0, image, this);
}
g.drawString("Y: " + MiddlePanel.y ,350,15);
}
}
The reason for doing it this way is you don't (really) control the placement of the image within a JLabel (lots of things can affect it's positioning).
Another solution would be to draw the text directly onto the BufferedImage itself. Which you would use would depend on how dynamic the text might be and a bunch of other factors
A way to do this is doing the exact inverse of your example, overriding the JPanel's paint method painting a BufferedImage (creating a background with your image), and then you can normally add the JLabel with text on your JPanel extension.
Please note that if JPanel is resized and you don't want to have a bad quality background, you'll have to manually create a resized version to adapt the container, or, at least, resize your buffered image with a little logic to keep Width/Height ratio... not that easy!
For the basic version you can try something like the following (taken from a working example) paintComponent overridden function:
#Override
protected void paintComponent(Graphics g) {
Image background = backgroundImage.getScaledInstance(this.getWidth(), this.getHeight(), Image.SCALE_DEFAULT);
super.paintComponent(g);
if (backgroundImage != null) {
g.drawImage(background, 0, 0, null);
}
}
Hope this helps ;)
I’ve been reading the API for Graphics2D and have seen examples of all the available composite modes (that are similar to photoshop blend modes) but I can’t see a way to draw a source image to a target buffered image In a colour that I have specified, for example my source image is a white opaque circle on a fully transparent background, how do I draw using this to a buffer so a coloured circle is drawn.
I would prefer not to construct an intermediate image for performance reasons, is this possible with the api?
EDIT: I have added an image that hopefully helps to show the operation I am trying to describe. This is a common way to draw sprites in open GL etc and I am just wondering how to use the Graphics2D API to do the same thing.
Is is possible using the API but you have to write your own ImageProducer subclass similar to FilteredImageSource but with two input images instead of one. But because of that the end result will require more lines of code than a manual implementation and won't be any more efficient. Alternatively you can use the existing FilteredImageSource and write an ImageFilter subclass that wraps the 2nd image and does the hard work.
Poke me if you decide you want to go with any of these routes.
Specify the location of your image in the imageName below.
public class ColoredCircle extends JPanel {
JFrame frame = new JFrame();
BufferedImage buf;
String imageName = "F://ngc_1300_spiral.jpg";
public static void main(String[] args) {
new ColoredCircle().start();
}
int scale = 10;
public void start() {
try {
buf = ImageIO.read(new File(imageName));
}
catch (IOException ioe) {
ioe.printStackTrace();
}
setPreferredSize(
new Dimension(buf.getWidth() / scale, buf.getHeight() / scale));
frame.add(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(buf,
0,
0,
buf.getWidth() / scale,
buf.getHeight() / scale,
null);
g2d.dispose();
}
}
I have a JFrame which has 4 different Panels. The Black box on right in the image below is the Image Panel. I am trying to write a Class that will allow me to load an image into any Panel within any other class in my program.
http://sdrv.ms/14TEq2T
LoadImage.java
package sf;
import java.awt.*;
import java.awt.image.*;
import javax.swing.ImageIcon;
public class LoadImage extends Component {
BufferedImage img;
public void paint(Graphics g) {
g.drawImage(img, 0, 0, null);
}
public LoadImage(String filename) {
try {
System.out.println(filename);
img = new ImgUtils().scaleImage(380, 360, filename);
} catch (Exception e) {
System.out.println("File not found");
}
}
class ImgUtils {
public BufferedImage scaleImage(int WIDTH, int HEIGHT, String filename) {
BufferedImage bi = null;
try {
ImageIcon ii = new ImageIcon(filename);
bi = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(ii.getImage(), 0, 0, WIDTH, HEIGHT, null);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return bi;
}
}
}
Code that I use to load in the Image in my other Classes.
private void getProductImage() {
try {
String path = getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");
String newPath = decodedPath.replace("build/classes/", "src/productImages/");
productImagePanel.add(new LoadImage(newPath + imageCode + ".jpg"));
revalidate();
pack();
} catch (Exception e) {
e.printStackTrace();
}
}
The 'imageCode' is the code that is retrieved from database once the Window is visible and I have checked the Path to images several times.
The LoadImage.java works on its own and load the images if a 'main runnable' method is added to it, however I can't seem to display the image in the panel I want. Please advice on how to fix my problem, any help is appreciated!
Your problem could very well be you're trying to load the image as a component to the JPanel. Problems include:
the preferredSize of the Component could well be [0, 0], and so it can be trying it's little heart out to display an image but just be too small to do so.
There could be other components already added to the JPanel
The JPanel's layout may not play nice with newly added components.
You shouldn't mix heavy weight (Component) with light weight (most all other non-top level Window Swing components) without a definite need.
I suggest:
Add a JLabel to your image displaying JPanel just once on JPanel creation.
Give your productImagePanel a method that accepts an Image or an ImageIcon and then either creates the ImageIcon from the Image or uses the ImageIcon provided to set the Icon of the JLabel.
Be sure that the JPanel uses a layout that allows the JLabel to display itself fully. The layout manager tutorials can help with this.
Either that or all the image displaying JPanel is for is to show the image and nothing else, get rid of it and instead use a JLabel by itself, and add your Icons directly to it.
Also as an aside: you should be disposing any Graphics and Graphics2D objects that you create (but not any given to you by the JVM). That means that when you're done drawing with g2d in your ImageUtilities, dispose of it.
I'm making my first simple game, that looks like Space Invaders.
I have used paint for drawing my hero on my JPanel. Now I guess if it's possible, in a simple way, to add a background image on my JPanel.
ImageIcon img = new ImageIcon(this.getClass().getResource("back.gif"));
Image image = img.getImage();
setDoubleBuffered(true);
hero = new Hero("hbarrel.gif",350,500);
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(hero.getImage(), hero.getX(), hero.getY(), this);
g2d.drawImage(image,0,0,this);
// Toolkit.getDefaultToolkit().sync();
g.dispose();
}
So, this is it: I tried to use my background img as hero img, and it works! but when I use the code above it only paints my hero img.... so it isn't a resource position issue.
Override paintComponent(Graphics) method and use Graphics.drawImage() to do that in your own custom component.
Well, try to paint the background image first and then the hero so that you have hero above background image
How to set background Image of JOptionPane? I want to show a different image on background of an JOptionPane.
You could extend the JOptionPane class and override the paint method.
Edit:
Depending on the image resolution and quality you might be able to stretch it with an AffineTransform during the WindowResize events without to much distortion. This would let you handle the JOptionPane and image size discrepancies mentioned below.
class ImageBackgroundPane extends JOptionPane
{
private BufferedImage img;
public ImageBackgroundPane (BufferedImage image)
{
this.img = image;
}
#Override
public void paint(Graphics g)
{
//Pick one of the two painting methods below.
//Option 1:
//Define the bounding region to paint based on image size.
//Be careful, if the image is smaller than the JOptionPane size you
//will see a solid white background where the image does not reach.
g.drawImage(img, 0, 0, img.getWidth(), img.getHeight());
//Option 2:
//If the image can be guaranteed to be larger than the JOptionPane's size
Dimension curSize = this.getSize();
g.drawImage(img, 0, 0, curSize.width, curSize.height, null);
//Make sure to paint all the other properties of Swing components.
super.paint(g);
}
}