In the code I have written, I am trying to determine when two Rectangle2D shapes have intersected. However when I run the code, the intersect method always returns true even when the shapes are clearly not. If anyone has any insight into this issue I would greatly appreciate it.
Graphics2D g2 = (Graphics2D) getGraphics();
FontRenderContext context = g2.getFontRenderContext();
Rectangle2D rectangleOne = fontOne.getStringBounds(blockOne, context);
Rectangle2D rectangleTwo= fontTwo.getStringBounds(blockTwo, context);
if(rectangleOne.intersects(rectangleTwo)){ ...
The getStringBounds method returns a logical bound. To obtain the Graphical bound, use TextLayout.getBounds instead.
Example:
Font font = Font.getFont("Helvetica-bold-italic");
FontRenderContext frc = g.getFontRenderContext();
TextLayout layout = new TextLayout("This is a string", font, frc);
Related
This code snippet creates an image which contains text. I set the font to Serif. However, when I query the resulting image later on for its font face, it returns Dialog. I don't understand why this is.
BufferedImage img = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.drawImage(img, 0, 0, 200, 100, this); // "this" refers to my custom JPanel which I am setting in the JFrame.
g2d.setPaint(Color.red);
g2d.setFont(new Font("Serif", Font.BOLD, 20));
System.out.println("from g2d object: " + g2d.getFont().getFamily()); // outputs "Serif"
String s = "Hello, world!";
FontMetrics fm = g2d.getFontMetrics();
int x = img.getWidth() - fm.stringWidth(s) - 5;
int y = fm.getHeight();
g2d.drawString(s, x, y);
g2d.dispose();
System.out.println("from image: " + img.getGraphics().getFont().getFamily()); // outputs "Dialog" (expected "Serif")
I understand that Dialog is one of the logical fonts in Java, but if the font is set to be something else, and Font.getFontName() returns the font face for the given font, why isn't it returning Serif as set in the Graphics2D object?
UPDATE: Calling g2d.dispose() before or after the last System.out.println() makes no difference. Both ways, it still prints out Dialog.
BufferedImage.getGraphics() returns the result of BufferedImage.createGraphics(). And, following the trail, we end up at that method of SunGraphicsEnvironment:
/**
* Returns a Graphics2D object for rendering into the
* given BufferedImage.
* #throws NullPointerException if BufferedImage argument is null
*/
public Graphics2D createGraphics(BufferedImage img) {
if (img == null) {
throw new NullPointerException("BufferedImage cannot be null");
}
SurfaceData sd = SurfaceData.getPrimarySurfaceData(img);
return new SunGraphics2D(sd, Color.white, Color.black, defaultFont);
}
We can clearly see that it uses the defaultFont, hardly connected to the image (unless getPrimarySurface() does change the defaultFont - I guess not [I could not find it being changed]).
Source code can be found here
Setting the Font of a Graphics will not change anything in a BufferedImage. The Font is used by the Graphics to draw the text onto the image. If a new Graphics is obtained from the image (using getGraphics() or createGraphics()), it will have the defaultFont as defined in the GraphicsEnvironment.
Do this:
BufferedImage img = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.drawImage(img, 0, 0, 200, 100, null); // "this" refers to my custom JPanel which I am setting in the JFrame.
g2d.setPaint(Color.red);
g2d.setFont(new Font("Serif", Font.BOLD, 20));
System.out.println("from g2d object: " + g2d.getFont().getFamily()); // outputs "Serif"
String s = "Hello, world!";
FontMetrics fm = g2d.getFontMetrics();
int x = img.getWidth() - fm.stringWidth(s) - 5;
int y = fm.getHeight();
g2d.drawString(s, x, y);
System.out.println(g2d.getFont().toString()+"-"+img.getGraphics().getFont().toString()+" from image: " + img.getGraphics().getFont().getFamily());
g2d.dispose();
System.out.println("from image: " + img.getGraphics().getFont().getFamily());
As you can see g2d retains its beloved Serif notation. The image is a thing of itself. Each time you call createGraphics on the image you get a new thing.
Everyone is making this more complicated than it needs to be. The answer is quite simple: the getGraphics() method of Image always creates a brand new Graphics object. From the documentation:
Creates a graphics context for drawing to an off-screen image.
That’s all there is to it. You set the font in one Graphics object, then you created another Graphics object. Of course the new Graphics object doesn’t know anything about the state of the first Graphics object. That would be like expecting that turning on one car’s headlights could somehow cause all cars to turn on their headlights.
You can get the expected result by only calling getGraphics() once.
System.out.println("from image: " + g2d.getFont().getFamily());
TL:DR The font is not accessible in Graphics or Graphics2D.
Whether you invoke BufferedImage#createGraphics() directly or BufferedImage#getGraphics() the end result is the same: they both create a new graphics object. More specifically, the former returns a new Graphics object and the latter returns a Graphics2D object. Both are abstractions of the concrete type returned which is an instance of SunGraphics2D. Unfortunately, this object does not store any information set, related to the font, in the graphics object. So basically, I cannot get the data I need from the image object.
In contrast, ProxyGraphics2D and PeekGraphics - both subtypes of the abstract class Graphics2D class do store such information in a Graphics2D global variable called mGraphics. This object is accessed via the getDelegate() method, which is obviously not part of the Graphics or Graphics2D API. Unfortunately, both of these subclasses are part of the sun package which is no longer accessible. Examining these classes clearly shows that methods like setFont() do save the font in this delegate (Graphics2D) object.
I am drawing a rectangle from method DrawRect using swings like this -
Graphics2D graph2 = (Graphics2D) g;
Rectangle2D rect = new Rectangle2D.Double(100, 100, 100, 100);
graph2.draw(rect);
In other method getDrawnRect, I want to get that object of drawn rectangle and read its properties.
I mean, is there any method available that returns objects drawn (like rectangles,circles) or any other way to get those objects indirectly.
Instead of the local variable Rectangle2D rect define a field of the class. During drawing store the rect to the field and then your getDrawnRect() method should return the stored rectangle field
Is there a way to calculate the length of a string in pixels, given a certain java.awt.Font object, that does not use any GUI components?
that does not use any GUI components?
It depends on what you mean here. I'm assuming you mean you want to do it without receiving a HeadlessException.
The best way is with a BufferedImage. AFAIK, this won't throw a HeadlessException:
Font font = ... ;
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
FontMetrics fm = img.getGraphics().getFontMetrics(font);
int width = fm.stringWidth("Your string");
Other than using something like this, I don't think you can. You need a graphics context in order to create a FontMetrics and give you font size information.
You can use the Graphics2D object to get the font bounds (including the width):
Graphics2D g2d = ...
Font font = ...
Rectangle2D f = font.getStringBounds("hello world!", g2d.getFontRenderContext());
But that depends on how you will get the Graphics2D object (for example from an Image).
This gives the output of (137.0, 15.09375) for me. I have no idea what the units are, but it certainly looks proportionally correct and doesn't use Graphics2D directly.
Font f = new Font("Ariel", Font.PLAIN, 12);
Rectangle2D r = f.getStringBounds("Hello World! Hello World!", new FontRenderContext(null, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT));
System.out.println("(" + r.getWidth() + ", " + r.getHeight() + ")");
I needed to get length and width of a string before paintComponent was called so I could size the enclosing panel to the text dimensions. None of these techniques provided a sufficiently width and I did not have a Graphics object available. I resolved the issue by setting my font to "Monospaced".
How to get FontMetrics without use Graphics ? I want to get FontMetrics in constructor, now I do this way:
BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
FontMetrics fm = bi.getGraphics().getFontMetrics(font);
int width = fm.stringWidth(pattern);
int height = fm.getHeight();
No you do not necessarily need to get/use the graphics object:
Font font = new Font("Helvetica",Font.PLAIN,12);
Canvas c = new Canvas();
FontMetrics fm = c.getFontMetrics(font);
If you would now call c.getGraphics() it would return null. The canvas solution on the other hand will also work in headless mode.
Hmm... It is quite logical that you need graphics to get FontMetrics. Font height, width etc. can differ on various displays.
If you have some Component, you can use it for getting FontMetrics:
component.getFontMetrics(font);
I have a String and I want to paint it onto an image. I am able to paint points and draw lines, however, even after reading the Text part of the 2D Graphics tutorial, I can't figure out how I can take a String and paint it onto my drawing.
Unless I'm looking at the wrong tutorial (but it's the one I get whenever I search for anything about Java and painting Strings using Graphics or Graphics2D), I'm still stumped.
Check out the following method.
g.drawString();
The drawString() method will do what you need.
An example use:
protected void paintComponent(Graphics g){
g.setColor(Color.BLACK);
g.drawString(5, 40, "Hello World!");
}
Just remember, the coordinates are regarding the bottom left of the String you are drawing.
if you want to play with the shape of your string (eg: fill:red and stroke:blue):
Graphics2D yourGraphicsContext=(...);
Font f= new Font("Dialog",Font.PLAIN,14);
FontRenderContext frc = yourGraphicsContext.getFontRenderContext();
TextLayout tl = new TextLayout(e.getTextContent(), f, frc);
Shape shape= tl.getOutline(null);
//here, you can move your shape with AffineTransform (...)
yourGraphicsContext.setColor(Color.RED);
yourGraphicsContext.fill(shape);
yourGraphicsContext.setColor(Color.BLUE);
yourGraphicsContext.draw(shape);