Draw AWT/Swing components indirectly? - java

I wanna know... is there a way to draw the components style outside from Frame/Applet?
I'm making a application that uses OpenGL, and I need a GUI with a good look, like AWT or Swing. Yes, I know that there are many libraries like Nifty and TWL, but I really want use AWT/Swing look.
Thanks. (And sorry for my bad english, I'm brazilian.)

You can render a component to an image, even if it is not displayable (although you will have to manually set the size to the preferred size):
c.setSize(c.getPreferredSize());
BufferedImage img = new BufferedImage(c.getWidth(), c.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
g.setComposite(AlphaComposite.Clear);
g.fillRect(0, 0, c.getWidth(), c.getHeight());
g.setComposite(AlphaComposite.SrcOver);
c.paintComponent(g);
g.dispose();
You can then use that image as a texture in OpenGL.
Of course, this will only give you a picture of the component; you won't be able to interact with it as you could with a "real" swing component.

Related

transparent .png background

I know Im not the first person to ask this type of question, but I think mines a little bit different.
I have a png image I drew on MS paint that is a player and I want the background of the image to be transparent when I use a graphics objects to draw the image. I tried some stuff with magic pink but It doesn't seem to be working the same in java. Im not new to java, but Im inexperienced so could you explain any packages or methods that you use thanks!
You will need to use AlphaComposite to have the transparency effect:
Assuming that you already know Graphics2D and Graphics uses BufferedImage
Creating temporary graphics object g.create() and then dispose the object for safely restore the state of graphics object changed after the object creation.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.drawImage(tileImage, 0, 0, getWidth(), getHeight());
g2d.dispose();
// draw player image
}
With Java6, a PNG picture should be used for TrayIcon, but as mentioned in this SO question, check:
the background color chosen to represent the transparent pixels
the transparency options
the resolution of the icon
alternate format like SVG (provided you are using external library like Batik, and
conversion mechnism to java.awt.Image)

Dedicated drawing surface in Java?

I want to do efficient 2D drawing in Java. I would like to have some kind of surface which I may draw freely without having to let the view hierarchy traverse and update, which may cause stutter.
I have used a JPanel at first and called repaint() but I find it not to be optimal (and it is the reason I ask). The closest thing I have worked with is the Android's SurfaceView and it gives me a dedicated drawing surface.
To achieve this dedicated drawing surface, do I need to use OpenGL or is there any equivalent SurfaceView?
If you don't need Accelerated Graphics, you can draw onto a BufferedImage with Graphics2D. Once you have your data in the BufferedImage, you can simply paint the BufferedImage onto the component. This will avoid any sort of flickering you are talking about.
Creating the BufferedImage is easy:
int w = 800;
int h = 600;
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Then you can draw objects onto it with a graphics context (Possibly in your own render function):
Graphics2D g = bi.createGraphics();
g.drawImage(img, 0, 0, null);
//img could be your sprites, or whatever you'd like
g.dipose();//Courtesy of MadProgrammer
//You own this graphics context, therefore you should dispose of it.
Then when you repaint your component, you draw the BufferedImage onto it as one piece:
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(bi, 0, 0, null);
}
Its sort of like using BufferedImage as a back buffer, and then once you are done drawing to it, you repaint it onto the component.

Blending images in java

Well I've got my game engine running smoothly, and perfectly on all machines! Before I continue adding functionality to the engine, I want to enhance the engine's graphical capabilities. The one I'm focused on is fading and blending images. I'm going to need some smooth transitions, so without using any 3rd party libraries like OpenGL, how does one apply opacity to images when drawing to a graphics object?
thanks for any replies :D
Perhaps using an AlphaComposite could be what you're looking for?
Image image = new Image(...);
float alpha = 0.5;
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
g2d.setComposite(composite);
g2d.drawImage(image, 0, 0, null);
}
You would set your alpha to whatever transparency level you desire (between 0.0 and 1.0). In this case, you would probably want to be using AlphaComposite.SRC_OVER to be able to overlay your transparent image and see behind it, unless your going for something else (if so, you can easily see all available constants and their explanations on the first link provided).

How can you produce sharp paint results when rotating a BufferedImage?

One attempted approach was to use TexturePaint and g.fillRect() to paint the image. This however requires you to create a new TexturePaint and Rectangle2D object each time you paint an image, which isn't ideal - and doesn't help anyway.
When I use g.drawImage(BufferedImage,...), the rotated images appear to be blurred/soft.
I'm familiar with RenderingHints and double-buffering (which is what I'm doing, I think), I just find it difficult to believe that you can't easily and efficiently rotate an image in Java that produces sharp results.
Code for using TexturePaint looks something like this.
Grahics2D g2d = (Graphics2D)g;
g2d.setPaint(new TexturePaint(bufferedImage, new Rectangle2D.Float(0,0,50,50)));
g2d.fillRect(0,0,50,50);
I'm using AffineTransform to rotate a hand of cards into a fan.
What would be the best approach to paint good-looking images quickly?
Here is a screenshot:
The 9 is crisp but the rest of the cards are definitely not as sharp.
It could be possible that the problem lies in when I create each card image and store it in an array.
Here's how I'm doing it at the moment:
// i from 0 to 52, card codes.
...
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
BufferedImage img = gc.createCompatibleImage(86, 126, Transparency.TRANSLUCENT);
Graphics2D g = img.createGraphics();
setRenderingHints(g);
g.drawImage(shadow, 0, 0, 86, 126, null);
g.drawImage(white, 3, 3, 80, 120, null);
g.drawImage(suit, 3, 3, 80, 120, null);
g.drawImage(value, 3, 3, 80, 120, null);
g.dispose();
cardImages[i] = img;
}
private void setRenderingHints(Graphics2D g){
g.setRenderingHint(KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
}
How should I approach this differently?
Thanks.
Edit:
Without RenderingHints
Setting AA hints made no difference. Also, setting RenderingHints when creating the images makes no difference either. It's only when they are being rotated with AffineTransform and painted using g.drawImage(...) that they seem to blur. The image above shows the difference between default (nearest neighbor) and bilinear interpolation.
Here is how I'm currently painting them (much faster than TexturePaint):
// GamePanel.java
private void paintCard(Graphics2D g, int code, int x, int y){
g.drawImage(imageLoader.getCard(code), x, y, 86, 126, null);
}
// ImageLoader.java
public BufferedImage getCard(int code){
return cardImages[code];
}
All my cards are 80x120 and the shadow .png is 86x126, so as to leave 3px semi-transparent shadow around the card. It's not a realistic shadow I know, but it looks okay.
And so the question becomes... How can you produce sharp paint results when rotating a BufferedImage?
Reference to a previous question also regarding a fanned card hand:
How can you detect a mouse-click event on an Image object in Java?
Bounty-Edit:
Okay so after much discussion I made a few test .svg cards to see how SVG Salamander would go about rendering them. Unfortunately, the performance is terrible. My implementation is clean enough, seeing as with double-buffered BufferedImage's the painting was incredibly fast. Which means I have come full circle and I'm back to my original problem.
I'll give the 50 bounty to whoever can give me a solution to get sharp BufferedImage rotations. Suggestions have been to make the images bigger than they need to be and downscale before painting, and to use bicubic interpolation. If these are the only possible solutions, then I really don't know where to go from here and I may just have to deal with the blurred rotations - because both of those impose performance setbacks.
I can finish my game if I can find a way to do this well.
Thanks to everyone. :)
When you rotate a rasterized image (such as a BufferedImage), you lose data. The best solution is to save your images larger than you'll need them, and downscale on the fly when you paint them. I've found that 1.5x the size you need is a good starting point.
Then, when you're painting the image, resize on the fly:
g.drawImage(bufferedImage, x, y, desiredWidth, desiredHeight, observer);
Rotations using bilinear interpolation is recommended.
Credit for suggestion goes to guido.
This advice is probably a little late in your design, but may be worth mentioning.
Rasterized images is probably the wrong technology to use if a lot of rotations and animations are a part of your UI; especially with complicated images with lots of curves. Just wait until you try and scale your canvass. I might suggest looking at a vector based graphical library. They will render the sorts of effects you want with less potential for artifacts.
http://xmlgraphics.apache.org/batik/using/swing.htm
Setting the interpolation type, as well as anti-aliasing value, in an AffineTransformOp may offer some improvement. Type TYPE_BICUBIC, while slower, is typically the best quality; an example is outlined here. Note that you can supply multiple RenderingHints. Another pitfall arises from failing to apply the hints each time the image is rendered. You may also need to adjust the transparency of the background, as suggested here. Finally, consider creating an sscce that includes one of your actual images.

How to draw a JPanel on a canvas?

is there a possibility to draw a JPanel on a specific location op a Graphics (or Graphics2D) object?
I override the paint method of my canvas, and call panel.paint(g) in there, but it does not work the way I woul hope.
#Override
public void paint(Graphics g){
Dimension size = panel.getPreferredSize();
panel.setBounds(pos.x, pos.y, size.width, size.height);
panel.paint(g);
}
the size object is correctly defined as I would wish, so that's not the problem. Also, the pos contains a correct x and y on the screen.
You should probably be using paintComponent instead of paint, since the latter is the AWT method, and the former is the Swing method.
One nice thing about Swing's paintComponent is that the Graphics passed is actually always going to be a Graphics2D, so you can:
Graphics2D g = (Graphics2D)lg;
Now you can use the getTransform to save the old transform, then modify the transform of the Graphics2D using either setTranform or the scale, translate and rotate methods. Don't forget to restore the old transform, or you'll likely fudge the next thing being drawn by that context.
I'll throw in that, depending on the circumstance, drawing to a BufferedImage might be appropriate. You can get a Graphics context using BufferedImage.getGraphics(). Then you can draw the BufferedImage's context by whatever means suit you.

Categories

Resources