1. 程式人生 > >Java Font 居中 反鋸齒效果

Java Font 居中 反鋸齒效果

Java Font 居中 和 抗鋸齒下效果

居中

看到網上經常有這樣的一些頭像,是純色加上第一個文字,類似於這樣子的:
我們也想自己做一套,考慮到有很多端都要用,因此選擇在服務端實現這樣的頭像。開發語言是Java。 在java裡面往圖片裡面寫一段文字一般採用 Graphic類的drawString方法,看下drawString方法的介紹:
public abstract void drawString(String str,
              int x,
              int y)
Draws the text given by the specified string, using this graphics context's current font and color. The baseline of the leftmost character is at position (x
y) in this graphics context's coordinate system. 顯然此處的str欄位只需要寫一個字元的即可。x和y表示的是起始的位置,在這兒和影象的不大一樣,指的是右下角的位置。
根據要求我要生成的圖片大小是216*216的,字型大小是136px。 對於ASCII碼錶上面的字母、字元和數字,通常寬度都是為漢字的一半,因此在呼叫的時候要注意好起始點的間距。拿漢字來舉例的話,應該文字是處在 (40,40)到 (176,176)的正方形裡面。因此此處的x和y我填寫的是40和176. 看下生成的圖片:
綠色的線表示的就是(40,40)到(176,176)的正方形。可以看到在x軸上面是居中的,但是在y軸上卻明顯地偏下方。那麼到底偏了多少,怎麼補償呢?不能瞎算,此處肯定跟字型是有關係的!搜尋沒得要領(估計是自己沒找對關鍵字),然後幸好手頭有本《Java核心技術 卷1:基礎知識》,看了看裡面字型的一節,解答了我的疑惑。 其實在這個類的說明裡面指出了一些線索,不過剛接觸的時候很難知道有這個類: FontMetrics   裡面有段話是這樣的:

When an application asks to place a character at the position (xy), the character is placed so that its reference point (shown as the dot in the accompanying image) is put at that position. The reference point specifies a horizontal line called the baseline of the character. In normal printing, the baselines of characters should align。

意思是,我們設定x和y的時候實際上設定的是參考點的位置,參考點就是上面的那個點。參考點所在的水平線是 baseline 基線,最上面的線是坡頂(ascenter),, 最下面的線是坡底(descenter)。坡頂到基線的距離是 上坡度(ascent), 坡底到基線的距離是下坡度。 再看一下Baseline的wikipedia,有這樣的一幅圖也很形象:
那麼知道字型的上坡度和字型的下坡度是否能夠解決問題了?試一下! (1) 怎麼知道下坡度? 下坡度可以用LineMetrics的 getDescend()方法解決。 (2)怎麼知道上坡度?在書上上坡度有點噁心,需要這樣子做: 
		FontRenderContext context = g2.getFontRenderContext(); 
		Rectangle2D bounds = f.getStringBounds(str, context);
                double ascend = -bounds.getY();
 但實際上用LineMetrics的getAscend() 方法就可以了。 (3)計算下x,y的位置, 對於水平方向的位置,很簡單:
                double x = (bufferedImage.getWidth() - 136) /2;
      對於垂直方向上的位置,兩邊留空白是: height - (ascend + descend)/ 2;
      注意字的位置不是左上角算起的,因此套住字的左下角的框框是: height - 上面的式子 = (height + ascend + descend) / 2;
      再注意,x,y指的是baseline的,因此還需要減去一個descend的距離,因此最終應該是 height + ascend - descend的距離。
看看生成的結果:
已經很讚了!
但是下面幾個點還需要仔細探索下:
字型的size 指的是 point size, (猜測)意思應該是字型的佔的畫素點的數量,但是這個指的是高度還是寬度?
從高度來看:“回”字的ascend是 126.4375, descend是:9.5625, 加起來正好是136。 這樣看來是高度啦。那麼實際上應該也不需要求字型的ascend了, 只需要
y = (height + 136)/ 2 - descend就可以了!
抗鋸齒效果 前面的“回”字都是橫豎筆畫,來個斜的筆畫的: 可以看到在撇捺的地方很毛糙影響美觀。這是因為沒有開啟抗鋸齒模式。抗鋸齒模式會對上面的部分進行計算和優化減少毛邊。 實現起來簡單呼叫下就行了: 
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
現在看下結果:

差別還是很明顯的!