código de WhiteFang34 es útil en combinación con el método siguiente que devuelve la altura real de una cadena específica. Puede ser un poco lento para renderizado en tiempo real, especialmente para fuentes/cadenas de caracteres grandes y estoy seguro de que se puede optimizar aún más, pero por ahora cumple mis propias necesidades y es lo suficientemente rápido como para ejecutarse en un proceso de fondo.
/*
* getFontRenderedHeight
* *************************************************************************
* Summary: Font metrics do not give an accurate measurement of the rendered
* font height for certain strings because the space between the ascender
* limit and baseline is not always fully used and descenders may not be
* present. for example the strings '0' 'a' 'f' and 'j' are all different
* heights from top to bottom but the metrics returned are always the same.
* If you want to place text that exactly fills a specific height, you need
* to work out what the exact height is for the specific string. This method
* achieves that by rendering the text and then scanning the top and bottom
* rows until the real height of the string is found.
*/
/**
* Calculate the actual height of rendered text for a specific string more
* accurately than metrics when ascenders and descenders may not be present
* <p>
* Note: this method is probably not very efficient for repeated measurement
* of large strings and large font sizes but it works quite effectively for
* short strings. Consider measuring a subset of your string value. Also
* beware of measuring symbols such as '-' and '.' the results may be
* unexpected!
*
* @param string
* The text to measure. You might be able to speed this process
* up by only measuring a single character or subset of your
* string i.e if you know your string ONLY contains numbers and
* all the numbers in the font are the same height, just pass in
* a single digit rather than the whole numeric string.
* @param font
* The font being used. Obviously the size of the font affects
* the result
* @param targetGraphicsContext
* The graphics context the text will actually be rendered in.
* This is passed in so the rendering options for anti-aliasing
* can be matched.
* @return Integer - the exact actual height of the text.
* @author Robert Heritage [[email protected]]
*/
public Integer getFontRenderedHeight(String string, Font font, Graphics2D targetGraphicsContext) {
BufferedImage image;
Graphics2D g;
Color textColour = Color.white;
// In the first instance; use a temporary BufferedImage object to render
// the text and get the font metrics.
image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
g = image.createGraphics();
FontMetrics metrics = g.getFontMetrics(font);
Rectangle2D rect = metrics.getStringBounds(string, g);
// now set up the buffered Image with a canvas size slightly larger than
// the font metrics - this guarantees that there is at least one row of
// black pixels at the top and the bottom
image = new BufferedImage((int) rect.getWidth() + 1, (int) metrics.getHeight() + 2, BufferedImage.TYPE_INT_RGB);
g = image.createGraphics();
// take the rendering hints from the target graphics context to ensure
// the results are accurate.
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, targetGraphicsContext.getRenderingHint(RenderingHints.KEY_ANTIALIASING));
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, targetGraphicsContext.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING));
g.setColor(textColour);
g.setFont(font);
g.drawString(string, 0, image.getHeight());
// scan the bottom row - descenders will be cropped initially, so the
// text will need to be moved up (down in the co-ordinates system) to
// fit it in the canvas if it contains any. This may need to be done a
// few times until there is a row of black pixels at the bottom.
boolean foundBottom, foundTop = false;
int offset = 0;
do {
g.setColor(Color.BLACK);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.setColor(textColour);
g.drawString(string, 0, image.getHeight() - offset);
foundBottom = true;
for (int x = 0; x < image.getWidth(); x++) {
if (image.getRGB(x, image.getHeight() - 1) != Color.BLACK.getRGB()) {
foundBottom = false;
}
}
offset++;
} while (!foundBottom);
System.out.println(image.getHeight());
// Scan the top of the image downwards one line at a time until it
// contains a non-black pixel. This loop uses the break statement to
// stop the while loop as soon as a non-black pixel is found, this
// avoids the need to scan the rest of the line
int y = 0;
do {
for (int x = 0; x < image.getWidth(); x++) {
if (image.getRGB(x, y) != Color.BLACK.getRGB()) {
foundTop = true;
break;
}
}
y++;
} while (!foundTop);
return image.getHeight() - y;
}
solo curiosidad, ¿qué estás tratando de hacer? – kleopatra
Intentando optimizar un diseño de texto para hacer el mejor uso del tamaño de pantalla disponible –