2011-04-29 61 views
5

可以很容易地確定使用FontMetrics字體的呈現高度,但對於周圍的其他方式?我怎樣才能獲得一個字體,將適合像素的特定高度?的Java:獲取字體與特定的高度以像素爲單位

「給我Verdana從上行到下行30個像素的高度。」

我怎麼問Java的這種?

+0

只是好奇 - 你想做什麼? – kleopatra 2011-04-29 12:09:02

+0

試圖優化文本佈局,以最大限度地利用可用的顯示尺寸 – 2011-04-29 13:48:56

回答

5

仁,

我不認爲有一個「直接」的方式來找到一個字體的高度;只有間接的方法...通過循環測量尺寸,並測試每個的高度是< =所需的高度。

如果你正在做通過他們這一次,只是環......如果你這樣做「對飛」,然後做一個二進制搜索,它會更快。

乾杯。基思。

5

我不知道的方式,通過以像素爲單位的實際高度,以獲得一個字體。它取決於它使用的上下文,所以可能沒有比採樣最佳匹配更短的方法。從設計的高度開始尋找尺寸應該是相當快的。下面是一個例子方法,其確實的是:

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

WhiteFang34的代碼是在用下面的方法,它返回一個特定的字符串的實際高度相結合是有用的。實時渲染可能會有點慢,特別是對於大字體/字符串,我相信它可以進一步優化,但現在它滿足了我自己的需求,而且速度足以在後端進程中運行。

/* 
* 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

我知道這是一個很古老的問題,但有人可能會覺得這仍然是:

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

要計算需要一定的像素高度的點,你應該能夠使用如下:

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

我還沒有測試過這個,但它似乎適用於我用過的顯示器。如果我發現它不起作用的情況,我會報告回來。

對於我已經使用此係統標準字體,此設置一個大寫字母(即,上升)所提供的像素尺寸的高度。

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

當然,一些特定的字母實際像素高度將取決於字母和字體:如果您需要設置上升+下降到像素的大小,你可以使用FontMetrics修正值使用,所以如果你想確保你的「H」是一些確切的像素高,你可能仍然想使用其他答案中提到的反覆試驗方法。請記住,如果您使用這些方法來獲取要顯示的每個特定文本的大小(如@Bob建議的那樣),則最終可能會在屏幕上出現隨機字體大小混亂,其中像「ace 「將比」標籤「有更大的字母。爲了避免這種情況,我會選擇一個特定的字母或字母序列(「T」或「Tg」或其他),然後將其固定到像素高度一次,然後使用您從該處隨處獲得的字體大小。

+0

謝謝澄清這一點...我剛剛檢查和一個字體的大小18f似乎是我的30「顯示器運行從對接約1/4」端口......並且當我卸下筆記本電腦並使用其更小的屏幕時,也會出現1/4「......一個啓示! – 2016-05-09 14:55:19

相關問題