描述:

这两天排查公司一个作图软件Android客户端的bug,代码中使用了canvas绘制bitmap,并保存为单位元图, 通过单位元图再使用canvas绘制出一张平铺效果的大图,最后获得的大图始终都很模糊。

可能原因分析:

1-Paint未设置抗锯齿属性

1
paint.setAntiAlias(true);

2-保存单位元图到sdcard时候使用了压缩

3-读取单位元图文件,用canvas绘制时候,对单位元图做了矩阵缩放,导致最终的大图模糊

4-保存最终大图的bitmap到sdcard时被压缩了

问题解决:

1->4各检查一遍原因,发现单位元图加载到内存时候被做了矩阵缩放,导致元图本身就模糊了,修改了这个问题后,大图较之前清晰很多但依然不够清晰,最后从海量资料中,发现对canvas设置抗锯齿属性后,图片明显清晰。

1
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));

附:搜集资料中,发现一篇html5 canvas绘制图片模糊的问题

解决canvas画图模糊的问题

canvas 画图经常发现他是模糊的。解决这个问题主要从两个方面下手。

1、改变canvas渲染的像素

情况:画1像素的线条看起来模糊不清,好像更宽的样子。

解决方案

1
2
var ctx = canvas.getContext('2d');
ctx.translate(0.5, 0.5);

原理:大家都知道屏幕最小单位就是像素。假如把canvas放的足够大,我能看到下面样子。

每一个方格就是长和宽都为1px。当我们画1px线条时遵循像素的起止范围,我们能得到标准的细线。

但遗憾的是canvas的画法不一样。canvas的每条线都有一条无限细的“中线”,线条的宽度是从中线向两侧延伸的。如果我们还是从第2个像素点画一条线,那么线条的中线就会靠齐到第2个像素的起点,然后我们开始画了,问题也就来了:Canvas 的线条以中线向两侧延伸,而不是向某一边延伸(比如这里,如果只是往右侧延伸,那么我们的问题就不再是问题了),延伸过后我们的线条实际上是这样的:

但是计算机不允许出现<1px的图形。所以会做个折中,把两个像素都绘制了。如此一来,本来1px的线条,就成了看起来2px宽的线条。
如何解决这个问题,就是把线条中线和和像素中间点对齐就行了。

中间点位置很好找,向后移动0.5px。所以你们画线时可以这样:

1
2
3
4
5
ctx.moveTo(100.5,100.5);
ctx.lineTo(200.5,100.5);
ctx.lineTo(200.5,200.5);
ctx.lineTo(100.5,200.5);
ctx.lineTo(100.5,100.5);

或者

1
ctx.translate(0.5, 0.5);

2.设置显示比例

在浏览器的window变量中有一个devicePixelRatio的属性,该属性决定了浏览器会用几个(通常是2个)像素点来渲染1个像素,举例来说,假设某个屏幕的devicePixelRatio的值为2,一张100x100像素大小的图片,在此屏幕下,会用2个像素点的宽度去渲染图片的1个像素点,因此该图片在此屏幕上实际会占据200x200像素的空间,相当于图片被放大了一倍,因此图片会变得模糊。
**其实方案很简单,也很容易明白。我们可以创建一个两倍于实际大小的canvas,然后用css样式把canvas限定在实际的大小。
下面是实现具体代码例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var canvas = document.getElementById("canvas")
context= canvas.getContext("2d");
var devicePixelRatio = window.devicePixelRatio || 1;
var backingStoreRatio = context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
var ratio = devicePixelRatio / backingStoreRatio;
canvas.width = canvas.width * ratio;
canvas.width = canvas.height* ratio;
context.scale(ratio, ratio);
ctx.translate(0.5, 0.5);
ctx.lineWidth = 1;
ctx.moveTo(2.5, 2);
ctx.lineTo(98.5, 2);
ctx.lineTo(98.5, 98);
ctx.lineTo(2.5, 98);
ctx.lineTo(2.5, 2);
ctx.stroke();

如果css限定了诸如width: 100%;
请使用

1
2
var oldWidth = parseInt(window.getComputedStyle(canvas).width);
canvas.width = oldWidth * ratio;

之后再

1
canvas.style.width = oldWidth + 'px';

不然会有超出问题

来源:https://segmentfault.com/a/1190000004505090