I need help with the Graphics#drawString
method:
I want to correctly draw it and need correct calculations for text width/height
and text position
.
These are my two test texts:
<text id="first-text" x="100" y="100" underline="true" border-color="#FFFFFF" border-width="1" font-size="32">Test Text</text>
<text id="second-text" x="300" y="100" underline="true" border-color="#FFFFFF" border-width="1">Test Text</text>
Note: The drawn red dot is a debug pixel drawn to show the x, y coordinates passed into the drawString method.
First Problem:
I want to get this width and height (underline height included) seen here:
using paint.net shows me that the result height is different, I checked the debugger and font metrics stuff and nothing is exactly 27px
or 23px
(height without underline offset + width):
oracle description of FontMetrics:
https://docs.oracle.com/javase/tutorial/2d/text/measuringtext.html
according to this picture I would get the 24px
(height of text) via this calculation:
metrics.getMaxAcsent() + metrics.getMaxDescent
but this already gives me 40px
, when the real height with underline is only 27px
I also looked at string bounds:
and I looked into line metrics, which actually gives me underline information which is wrong though, as the underline offset and underline thickness is 4px
together:
So I have multiple problems getting correct values for this and I will continue asking questions about correct position if I fixed the height problem. If you need anymore specific information just ask.
xml schema (font default values):
<xs:attributeGroup name="font">
<xs:attribute name="font" type="xs:string" default="Sans Serif"/>
<xs:attribute name="font-size" type="xs:positiveInteger" default="12"/>
<xs:attribute name="font-color" type="hexType" default="#FFFFFF"/>
<xs:attribute name="bold" type="xs:boolean" default="false"/>
<xs:attribute name="italic" type="xs:boolean" default="false"/>
<xs:attribute name="underline" type="xs:boolean" default="false"/>
</xs:attributeGroup>
Draw method:
@Override
public void draw(Graphics2D graphics, int rootX, int rootY, int rootWidth, int rootHeight) {
Font derivedFont = font.font().deriveFont(Map.of(TextAttribute.SIZE, font.fontSize()));
if (font.bold()) {
derivedFont = derivedFont.deriveFont(Font.BOLD);
}
if (font.italic()) {
derivedFont = derivedFont.deriveFont(Font.ITALIC);
}
if (font.underline()) {
derivedFont = derivedFont.deriveFont(Map.of(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON));
}
// FIXME: 12/04/2023 fix calculations
FontMetrics fontMetrics = graphics.getFontMetrics(derivedFont);
int textWidth = fontMetrics.charsWidth(text.toCharArray(), 0, text.length());
int textHeight = derivedFont.getSize();
BufferedImage textImage = new BufferedImage(textWidth + (border.width()*2) + 3, textHeight + (border.width()*2) + 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D textGraphics = textImage.createGraphics();
textGraphics.setComposite(AlphaComposite.Clear);
textGraphics.fillRect(0, 0, textImage.getWidth(), textImage.getHeight());
textGraphics.setComposite(AlphaComposite.SrcOver);
border.draw(textGraphics, 0, 0, textImage.getWidth()-1, textImage.getHeight()-1, textImage.getWidth(), textImage.getHeight());
textGraphics.setFont(derivedFont);
textGraphics.setColor(font.fontColor());
textGraphics.drawString(text, border.width() + 1, fontMetrics.getHeight()/2 + 5); // TODO: 12/04/2023 calculate correct y + correct height of full box
textGraphics.setColor(new Color(255, 0, 0));
textGraphics.drawOval(border.width() + 1, fontMetrics.getHeight()/2 + 5, 1, 1);
textGraphics.dispose();
}
Edit:
I just noticed aswell that the underline is not working correctly: