Java Font 居中 和 抗锯齿下效果
居中
看到网上经常有这样的一些头像,是纯色加上第一个文字,类似于这样子的:我们也想自己做一套,考虑到有很多端都要用,因此选择在服务端实现这样的头像。开发语言是Java。
在java里面往图片里面写一段文字一般采用 Graphic类的drawString方法,看下drawString方法的介绍: 链接: https://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html#drawString(java.lang.String,%20int,%20int)
public abstract void drawString(String str,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表示的是起始的位置,在这儿和图像的不大一样,指的是右下角的位置。
int x,
int 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 (x, y), 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();但实际上用LineMetrics的getAscend() 方法就可以了。(3)计算下x,y的位置, 对于水平方向的位置,很简单:
Rectangle2D bounds = f.getStringBounds(str, context);
double ascend = -bounds.getY();
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);现在看下结果:
差别还是很明显的!