canvas详解(3)-模糊问题

canvas详解(3)-模糊问题

1.模糊的原因

canvas绘图理论上应该是清晰的,但是有些屏幕上看到的确是模糊的,究其原因有3点:

css样式影响

canvas绘图是基于自身的宽高设置,必须明确指定宽高,不能使用百分比。如果出现线条锯齿状原因,一般都是因为,canvascss样式放大了原本的canvas图形导致的。例如:

<canvas id="test" width="200" height="100" style={{width:400,height:200}}></canvas>

css将canvas自身放大了一倍,导致图像不清晰

设备像素比

不同的设备,其物理像素/屏幕宽度是不一样,从而就导致了相同的屏幕宽度下,1px的物理像素有可能不再是1px。而设备像素比的不同是导致图像模糊的主要原因。

为了解决这一问题,我们需要完成如下步骤:

  • 获取设备像素比;
  • 将canvas宽高和图形放大相同的像素比倍数。(即所有的canvas图形都放大设备像素比倍数,包括文字);
  • 通过css将canvas缩小对应的倍数。

将图形整体放大是为了适应当前实际物理像素,这样绘制的图形才是最清晰的,但是因为放大后的图形不是我们想要的,所以必须用css缩小到相应的倍数,才能呈现出正常的图形。

需注意:canvas的scale只是对内部图形进行放大缩小,并不能改变画布大小。即是说放大后部分图形将可能不能显示,因为超出了画布范围。

线条绘制原理

canvas的线条绘制是以当前线条坐标为中心,左右各绘制指定lineWidth一半的宽度lineWidth默认是1px),而由于canvas无法在整个像素宽内只绘制半个像素,所以实际默认绘制的线条是2px的图形,只是因为默认被填充的半像素导致整体视觉颜色变浅了。

例如:

ctx.lineWidth = 1;
ctx.moveTo(50,50)
ctx.lineTo(150,50);
ctx.stroke();

绘制该线条的时候,canvas会在y轴为50的线上下各绘制0.5px,所以需要绘制的区域就是[49.5~50,50~50.5]这2个区域都是半像素区域canvas无法绘制,所以实际绘制的区域变成了[49~50,50~50],因为[49~49.5,50.5~51]是被额外填充区域,所以整体颜色变淡了。

既然找到了问题的原因,那么解决办法就相对好找了,我们只需让绘制的上下2部分都变成整像素的就OK了。

ctx.lineWidth = 1;
ctx.moveTo(50,50.5)
ctx.lineTo(150,50.5);
ctx.stroke();

我们将y轴增加0.5,那么绘制的时候就是以50.5轴线上下绘制0.5px,实际绘制区域变成了[50~50.5,50.5~51]

而50~51正好构成了一整个像素,canvas能够直接绘制,所以绘制的效果就是1px清晰效果。

当然绘制整数倍宽度的线条一般不会出现这种现象

ctx.lineWidth = 2;
ctx.moveTo(50,50)
ctx.lineTo(150,50);
ctx.stroke();

绘制结果为2px清晰线条

2.模糊解决方案

获取设备像素比
 //设备像素比
 getPixelRatio(context) {
        var backingStore = context.backingStorePixelRatio ||
            context.webkitBackingStorePixelRatio ||
            context.mozBackingStorePixelRatio ||
            context.msBackingStorePixelRatio ||
            context.oBackingStorePixelRatio ||
            context.backingStorePixelRatio || 1;
        return (window.devicePixelRatio || 1) / backingStore;
};
放大画布
 const ctx = canvas.getContext('2d');
 let ratio = this.getPixelRatio(ctx);
 let scale = ratio;
 this.setState({ ratio: 1 / ratio });//缓存缩小比例

当然这里还可以根据屏幕大小设置画布的缩放比例,但是无论画布怎么缩放,都必须让画布放大到屏幕的真实像素比,所有的图形、文字都应放大。

canvas提供了scale()方法用于缩放画布图形,但是该方法只是将画布中的图形在当前画布大小下缩放,实际画布还是原来的大小,只是内部图形被缩放了,这根本不能满足我们的业务场景,我们希望的效果是画布和其内部的图形等比缩放。所以我们只能在当前画布宽高下,对所有的图形进行等比重绘,这样就能达到想要的效果了。

将画布缩小到实际大小

因为我们按设备像素比将整个画布放大了,那么我们就需要通过css来还原它的显示大小。通过zoom属性,缩放整个画布。

<canvas id={this.props.canvasId} width={this.props.width} height={this.props.height} 
                style={{ zoom: this.state.ratio}}></canvas>

style中的内容才是重点。网上有很多说在父级进行缩放纯属扯淡。只能在canvas自身上缩放。

当然不用zoom,直接使用css定义width,height为对应比例的宽高效果也是一样的。

例如:

<canvas id={this.props.canvasId} width={this.props.width} height={this.props.height} 
                style={{ width: this.props.width*this.state.ratio,
                       height:this.props.height*this.state.ratio}}></canvas>

完整代码请参考:canvas详解(1)-原理

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Canvas 是 HTML5 中的一个元素,它提供了一种在网页上绘制图形、动画和视频的方法。要回执图像和视频,可以使用 Canvas 的 drawImage 方法。 要回执图像,首先需要创建一个 Image 对象,并将图像的路径指定给它。然后,可以使用 Canvas 的 drawImage 方法将图像绘制到 Canvas 上。这个方法接受几个参数,包括图像对象、图像的起始坐标以及可选的宽度和高度。 下面是一个回执图像的示例: ```javascript var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); var img = new Image(); img.onload = function() { ctx.drawImage(img, 0, 0, canvas.width, canvas.height); }; img.src = "path/to/image.jpg"; ``` 要回执视频,可以使用 HTML5 的 video 元素。首先,创建一个 video 元素,并将视频的路径指定给它。然后,可以使用 Canvas 的 drawImage 方法将视频绘制到 Canvas 上。与回执图像类似,这个方法接受几个参数,包括视频元素、视频的起始坐标以及可选的宽度和高度。 下面是一个回执视频的示例: ```javascript var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); var video = document.getElementById("myVideo"); video.addEventListener("play", function() { setInterval(function() { ctx.drawImage(video, 0, 0, canvas.width, canvas.height); }, 1000 / 30); }, false); video.src = "path/to/video.mp4"; ``` 这些示例代码演示了如何使用 Canvas 回执图像和视频。你可以根据自己的需求进行调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值