I want to copy part of one image into another smaller one: in other words, copy a subrectangle.
I have a Graphics2D object for the source, I can make one for the target, and I know about targetGraphics2D.drawImage(Image img,....) , but how do I get that img from the sourceGraphics2D?
Answer (per aioobe): The source needs to be an Image rather than a Graphics2D.
Image.subImage() is the method for getting the relevant part of the source.
As Aioobe said, you're not going to get the image from the Graphics2D alone. But if your sourceGraphics2D is coming from a Swing component you could try invoking its paint methods with your own Graphics2D instance. From there you can copy the interesting sub-region.
This is kind of a hack but it should work assuming you're using Swing objects.
class CopySwingPaintingSubRegion extends TheSourceType
{
private BufferedImage bufImg;
public CopySwingPaintingSubRegion()
{
bufImg = new BufferedImage(...);
//Draw the original image into our bufImg for copying
super.paintComponent(bufImg.createGraphics());
}
public BufferedImage getSubImage(int x, int y, int w, int h)
{
return bufImg.getSubImage(x,y,w,h);
}
}
Short answer: Yes, you can
A Graphics2D object that has been created on a buffered Image knows the image but isn't willing to hand it back to you. If you don't mind using reflection, you can steal it back (reflection). The following code demonstrates the approach:
public class Graphics2DReflector {
public static void main(String[] args) {
// prepare the Graphics2D - note, we don't keep a ref to the image!
final Graphics2D g2d =
new BufferedImage(100,100,BufferedImage.TYPE_INT_RGB).createGraphics();
g2d.drawString("Reflected", 10, 50);
JFrame frame = new JFrame("Reflected Image");
// one Panel to show the image only known by g2d
frame.getContentPane().add(new Panel() {
#Overwrite
public void paint(Graphics g) {
try {
SurfaceData data = ((SunGraphics2D) g2d).surfaceData;
Field bufImg = BufImgSurfaceData.class.getDeclaredField("bufImg");
bufImg.setAccessible(true);
BufferedImage image = (BufferedImage) bufImg.get(data);
g.drawImage(image,0,0,null);
} catch (Exception oops) {
oops.printStackTrace();
}
}
});
frame.setSize(200,200);
frame.setVisible();
}
}
Note: this depends on some Sun/Oracle classes and may not work with all Java VMs. At least it shows an approach and you may have to inspect the actual classes to get the fields.
If I understand it right, W3Schools has code to get part of an image to put on a canvas. If you need it as another image you could get it from that canvas.
I have one PNG image 20 tall by 200 wide that has 10 "cells or frames" - I use for animation and use the method below:
context.drawImage( img, sx, sy, swidth, sheight, x, y, width, height );
First, some notes regarding Andreas_D answer below:
His code relies on sun.java2d.SunGraphics2D which is an internal and undocumented OpenJDK class. This means that, while it might compile and run on your computer, it might will probably break if you distribute the code to other people. For a detailed discussion, see the official statement regarding this.
The code relies on reflection to pry the internal class open which is a code smell in it self.
All in all, his approach is an example of exceptionally bad practice (both when it comes to programming style and when it comes to helping fellow programmers to use the API correctly)
how do I get that img from the sourceGraphics2D?
I suspect you misunderstood the responsibility of the Graphics2D class.
You use the Graphics2D class to draw on something. It is capable of drawing on a BufferedImage (if you got the graphics object from a buffered image), the screen (if you got it as an argument to your paintComponent method) or even a printer. So in other words, given a Graphics2D objects, there might not even exist an image!
So, as you probably understand, the Graphics2D API does not provide methods for getting hold of the underlying image. (Such method wouldn't make sense, the graphics object might be passing on lines and text being drawn to a printer!)
To get hold of a subimage you need to get hold of the underlying image which the given graphics object draws upon.
Related
This is the code
player = createEntity(400, 600, 40, 60, Color.BLUE);
private Node createEntity(int x, int y, int w, int h, Color color) {
Rectangle entity = new Rectangle(w, h);
entity.setTranslateX(x);
entity.setTranslateY(y);
entity.setFill(color);
gameRoot.getChildren().add(entity);
return entity;
}
I'm not sure how to put an image to my player, any thoughts?
Java How can I put an image on a rectangle
My suggestion (if this is Swing) is not to use a Rectangle, or else use Rectangle but as part of a larger solution.
Instead I'd create a logical class, perhaps called Entity, that has a position, an image, and a draw method that accepts a Graphics parameter draws its image at whatever position needed, and then create Entity objects. Then within my JPanel's paintComponent method, I'd iterate through all the Entities created, calling their draw method.
First of all, you'll want to use active rendering. This'll prevent you from having all sorts of problems related to refreshing the display, and Java's BufferStrategy automatically handles multi-buffering for you, assuming you request more than one buffer.
Now that you're sure the screen gets updated, when rendering, you can draw a rectangle with a java.awt.Graphics object using the drawRect method. If you would like to fill this rectangle, use fillRect. The Graphics object draws everything in a pre-defined colour. If you would like to change colour, you can call setColor. This method requires a java.awt.Color object as an argument, which allows you to define all possible 64-bit transparent colours using one of the constructors. It also has a few predefined colours, like Color.RED, which is 0xFF0000.
I recommend you explore all the methods Graphics has to offer, and maybe even look into Graphics2D, which supports a few extra things. Note that most Graphics objects can be cast to Graphics2D, but if you're not sure, you might either want to look into Java's source code (there is an src.zip inside the JDK installation) or use an instanceof check. As a matter of fact, Graphics2D supports drawing shapes like your Rectangle using the drawShape or fillShape method.
For those of you who are curious, 0xFF0000 is a way of formatting colours. It is RGB encoded into hexadecimal (0xRRGGBB). It's also commonly represented #FF0000 in other languages, like CSS (Cascading Style Sheet, used for easily formatting HTML documents)
It is possible to draw from one Graphics2D to another Graphics2D?
Let me explain.
I have printing issues, when i display a JTextArea or JTextPanel in screen, internaly its used sun.java2d.SunGraphics2D, but when im printing its used sun.print.PeekGraphics and sun.awt.windows.WPathGraphics.
The problem is with some kind of Fonts, like Arial. In some sizes lines are cut.
I have tryed a lot of ways to render the text in printing, Graphics2D.drawString, SwingUtilities2.drawString, TextLayout.drawString, but in some cases lines are still cut, or lines are not cut but some kind of justification makes disapear white spaces.
So my idea is try to render components with sun.java2d.SunGraphics2D and "copy" the surface to the printer via sun.print.PeekGraphics or sun.awt.windows.WPathGraphics.
Thanks in advance.
Yes its possible, thats how double buffering is achieved in a lot of Java Games. What you need is the Graphics2D's drawImage() method which takes in another Graphics2D object to draw in. E.g. from a small game of mine:
private Main(){
...
/* Create the backbuffer as a BufferedImage object */
this.doubleBuffer = new BufferedImage(this.WIDTH, this.HEIGHT, BufferedImage.TYPE_INT_RGB);
/* create a Graphics 2D object to draw INTO this backbuffer */
this.doubleBufferG2D = (Graphics2D) doubleBuffer.createGraphics();
...
}
Somewhere else:
/*Now lets draw the backbuffer INTO the screen */
g2d.drawImage(doubleBuffer, null , 0, 0);
Edit: heh I realized its not exactly as above...lemme think on it.
Edit2: Alright the above can still be used a sample, but the sequence of steps to draw from one Graphics2D to another should be as such:
1. From a Graphics2D object to an Image/BufferedImage object using drawGraphics().
2. From the Image/BufferedImage above, extract its member Graphics2D object by using itscreateGraphics().
Looks like you can do one of two things:
create a Graphics2D on an image, do your rendering, then draw the image into another Graphics2D
or create Graphics2D from original Graphics2D using Graphics.create() methods and then do you rendering.
I'm currently working on a game in Java and am trying to create a background without using any image files. The image consists of a square split into 4 triangles, each of which is a different color.
If anyone could point me towards some was of using Graphics2D and then saving it to a BufferedImage, that would be great.
I recommend:
First create a BufferedImage using the constructor that takes three ints: a width, height, and a BufferedImage type, BufferedImage.TYPE_INT_ARGB would probably work well, and the width and height will likely be constants in your program.
You would extract a Graphics2D object out of the BufferedImage by calling its createGraphics() method.
Then draw with the Graphics object using its drawXXX(...) methods of which you have many to select from.
To change color, simply call setColor(Color c) on your Graphics/Graphics2D object.
When done drawing, be sure to dispose of your Graphics object via its dispose() method.
Edit as per Adrian Blackburn, check out the BufferedImage Tutorial as part of the standard Oracle Java tutorials.
I am doing a project in which I need to print the label/description of the line (drawn using graphics) with respect to orientation of the line.
Does anyone know how to do it?
Look to the Graphics2D methods such as rotate(), scale() & translate() - as well as the more general translate(AffineTransform) method.
See Transforming Shapes, Text, and Images in the Java tutorial for more details and working examples, especially of using an AffineTransform (which can concatenate scale, rotate, transform & shear operations).
You do not mention how you obtain the Graphics object. The Graphics object passed to Swing components in paintComponent(Graphics) will generally be a Graphics2D instance, and can be cast to one. To get a Graphics2D instance from a BufferedImage, call createGraphics().
Make a class called "Labelled line" and make it something like this
class LabeledLine {
private int x1, y1, x2, y2;
private String label;
public void drawOn(Graphics g) {
// need more features? thickness, etc? add it
g.drawLine(x1,y1,x2,y2);
// compute size of text, position of text, angle of text
// draw that text
}
}
A quick google for drawing angled text gave me a couple results, so that should be easy to do.
I'm Basically programming a simple game engine but I'm having problems with my sprites/images not appearing when they should... or at all!
I'll try and keep this as simple as possible. I have a Sprite, GameEngine and Display class. In the gameloop, I have a method that sets the new position of my Sprite (so it just sets the x and y variables). Next I call a transform method which does the following:
public void transform() {
affineTransform.setToIdentity();
affineTransform.translate(x, y);
}
Following that, I then call a draw method in the Sprite:
public void draw() {
graphics2D.drawImage(image, affineTransform, jFrame);
}
Finally, in my thread I then call repaint() on the JFrame (the Display class). My paint method for that class is as follows:
public void paint(Graphics g) {
g.drawImage(backbuffer, insets.left, insets.top, this);
}
But nothing is appearing, apart from a black screen!
I'm also getting confused between Graphics g, and Graphics2D and when to use either. (The overridden paint method uses Graphics g). For the record, I do have a Graphics2D variable in the class that is created by calling backbuffer.createGraphics();
Another thing that is confusing me is this AffineTransform... I've read the documentation but I'm still utterly confused on how and when to use it - and what exactly it seems to do. Is there any explanation in relatively simple terms?
Surely this should be working... am I missing something out here?
To answer part of your question:
From the Graphics2D JavaDoc
This Graphics2D class extends the Graphics class to provide more sophisticated control over geometry, coordinate transformations, color management, and text layout. This is the fundamental class for rendering 2-dimensional shapes, text and images on the Java(tm) platform.
Essentially, with Graphics2D you can do much more than you can with Graphics. And with a Sun JVM 1.5+, it should be safe to cast the Graphics object you get in paint() to Graphics2D
I just noticed this: For the record, I do have a Graphics2D variable in the class that is created by calling backbuffer.createGraphics();
You should make sure you're not drawing on a Graphics[2D] canvas (I'll use this term to refer to the drawable area that the Graphics[2D] object provides) that you later throw away. If you're drawing your image on a separate canvas, you should ensure that you then draw that image onto your actual display canvas.
I don't really have a good explanation of AffineTransform but maybe these will help?
http://www.javalobby.org/java/forums/t19387.html
https://secure.wikimedia.org/wikipedia/en/wiki/Affine_transformation
From Wikipedia - In general, an affine transformation is composed of linear transformations (rotation, scaling or shear) and a translation (or "shift"). Several linear transformations can be combined into a single one. Basically, you use this class to perform operations such as rotation, translation, zoom etc.