最后的一像素

771 阅读2分钟

「这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

最后的一像素

最近做的文字编辑的功能有点问题,在编辑之后,用canvas保存出来之后和原始的图片视图总是有一些偏差,这个偏差也不多,几个像素,发现它之后,心里是真的难受,于是开始尝试...

需求

我有一段文字的json数据,这段json数据无论是用Canvas画图,还是用TextView去显示,它都要能保持一致。

{
"x":0,
"y":0,
"size":1000,
"text":"M"
}

很简单的一段json,转化成对象,然后打上备注。

x - 左上角的x坐标 y - 左上角的y坐标 size - 文字的大小,单位是像素 text - 文字的内容

我的实现方法

画视图

直接使用View的setX、setY方法去控制View的显示,因为View的setX、setY也是左上角的坐标,所以直接设置进去即可。 完整的代码是这样。 (为了可以明显区分效果,我把文字大小设置成了1000)

TextView textView = new TextView(this);
textView.setX(mTextBean.getX());
textView.setY(mTextBean.getY());
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextBean.getSize());
textView.setText(mTextBean.getText());
textView.setBackgroundColor(Color.parseColor("#03DAC5"));
// 设置不抗锯齿
textView.getPaint().setAntiAlias(false);
container.addView(textView);

这里设置大小时指定像素单位,并设置了不抗锯齿,因为设置抗锯齿的话,会有渐变色,会影响我们的结论。

画Canvas

Canvas也是很普通的画一个文本,问题就是处在drawText这个方法,我以为它是左下角开始画,所以我使用了0 + mTextBean.getSize()作为Y坐标,这样是不可靠的!当时项目很紧张,就没有时间去在意它,它就被搁置了。

TextPaint textPaint = new TextPaint();
// 设置不抗锯齿
// textPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(mTextBean.getSize());
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
Bitmap baseBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(baseBitmap);
canvas.drawText(mTextBean.getText(), 0, 0 + mTextBean.getSize(), textPaint);
image.setImageBitmap(baseBitmap);

分析过程

TextView 的setX、setY代表左上角的坐标没什么问题。 但是Canvas中的drawText()就不仅仅是左下角这么简单了。

  • drawText() 的坐标和textPaint对齐方式有关

对齐方式有下面三种,分别对应的图片

图片来自 图片链接

Paint.Align.LEFT(默认)

1.png

Paint.Align.CENTER

2.png

Paint.Align.RIGHT

3.png

  • drawText() 参数中的y是baseLine(基线)

baseLine 相对复杂一些,还是图片理解的方便些。

4.png

drawText() 中参数的y,即对应着BaseLine,怎么将左上角的坐标移动到BaseLine呢?

再看另一张图,这张图代表着FontMetrics中的属性。

5.png

所以我们将json中的y + Math.abs(Top)就可以了。

修改过后的代码是这样。

canvas.drawText(mTextBean.getText(), 0, 0 + Math.abs(fontMetrics.top), textPaint);

效果图

11.jpg

遗留问题

通过效果图的对比发现,同样都是默认的Text的属性,但是左边到顶部的距离是20px,右边到顶部的距离是19px,这个1像素的差距是哪里来的???

Image [1].png

Image.png

猜测可能是是否包含baseLine的这条线的原因吧。我只能手动+1了。。