2011-04-29 15 views
5

Es fácil determinar la altura representada de una fuente usando FontMetrics, pero ¿qué pasa al revés? ¿Cómo puedo obtener una fuente que se ajuste a una altura específica en píxeles?Java: Obtener una fuente con una altura específica en píxeles

"Dame Verdana en un tamaño que tenga 30 píxeles de altura desde el ascendente al descender."

¿Cómo le pregunto a Java por esto?

+0

solo curiosidad, ¿qué estás tratando de hacer? – kleopatra

+0

Intentando optimizar un diseño de texto para hacer el mejor uso del tamaño de pantalla disponible –

Respuesta

5

Jen,

No creo que hay una manera "directa" para encontrar una fuente por la altura; solo de forma indirecta ... al recorrer los tamaños, y probar la altura de cada uno es < = altura requerida.

Si está haciendo esto una vez, simplemente en bucle ... si lo hace "sobre la marcha" y luego realiza una búsqueda binaria, será más rápido.

Saludos. Keith.

5

No conozco la forma de obtener una fuente por su altura real en píxeles. Depende del contexto en el que se utiliza, por lo que probablemente no haya una forma más corta que muestrear para la mejor coincidencia. Debería ser bastante rápido buscar tamaños hacia arriba o hacia abajo desde la altura diseñada. He aquí un ejemplo de método que hace eso:

public Font getFont(String name, int style, int height) { 
    int size = height; 
    Boolean up = null; 
    while (true) { 
     Font font = new Font(name, style, size); 
     int testHeight = getFontMetrics(font).getHeight(); 
     if (testHeight < height && up != Boolean.FALSE) { 
      size++; 
      up = Boolean.TRUE; 
     } else if (testHeight > height && up != Boolean.TRUE) { 
      size--; 
      up = Boolean.FALSE; 
     } else { 
      return font; 
     } 
    } 
} 
1

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; 
} 
5

Sé que esto es una pregunta muy antigua, pero alguien todavía podría encontrarlo:

The font height in Java (and many other places) is given in "typographic points", which are defined as roughly 1/72nd of an inch.

Para calcular los puntos necesarios para una determinada altura de píxeles, debe ser capaz de utilizar el siguiente:

double fontSize= pixelSize * Toolkit.getDefaultToolkit().getScreenResolution()/72.0; 

No he probado esto extensamente todavía, pero parece funcionar para los monitores que he usado. Informaré si alguna vez encuentro un caso en el que no funciona.

Para las fuentes de sistema estándar con las que he usado esto, establece el alto de una letra mayúscula (es decir, el ascenso) al tamaño de píxel proporcionado. Si es necesario configurar el ascenso + descenso hasta el tamaño de píxel, puede corregir el valor con el FontMetrics:

FontMetrics m= g.getFontMetrics(font); // g is your current Graphics object 
double totalSize= fontSize * (m.getAscent() + m.getDescent())/m.getAscent(); 

Por supuesto, el pixel-altura real de algunas letras específicas dependerá de la letra y la fuente utilizado, por lo que si desea asegurarse de que su "H" es una cantidad exacta de píxeles de alto, es posible que desee utilizar los métodos de prueba y error mencionados en las otras respuestas. Solo tenga en cuenta que si utiliza estos métodos para obtener el tamaño de cada texto específico que desea mostrar (como se sugirió @Bob), podría terminar con un tamaño de fuente aleatorio en su pantalla donde un texto como "as" "tendrá letras mucho más grandes que" Etiqueta ". Para evitar esto, elegiría una letra específica o una secuencia de letras ("T" o "Tg" o algo así) y lo arreglaría a su altura de píxel una vez y luego usaría el tamaño de fuente que obtenga de eso en todas partes.

+0

gracias por aclarar esto ... Acabo de comprobar y una fuente de tamaño 18f parece ser de aproximadamente 1/4 "en mi monitor de 30" ejecutado desde el acoplamiento puerto ... y también aparece 1/4 "cuando desacopla mi computadora portátil y uso su pantalla mucho más pequeña ... ¡una revelación! –

Cuestiones relacionadas