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.
CodePudding user response:
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.
CodePudding user response:
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.
CodePudding user response:
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());
CodePudding user response:
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.
