移动端canvas画图中遇到的坑

处理需求中,遇到一个图片重新绘制拼接的功能,如下图:动态的将二维码重新绘制到图片上面去
在这里插入图片描述

最开始想到的是有两种解决办法:

1、使用html2canvas插件去将html动态的生成为图片,html2canvas的功能就是可以将一个dom元素里面的全部内容重新绘制成一个图片,实现方式就是:通过css的手动,将二维码定位上去,然后用html2canvas去生成图片,再把原图进行覆盖,实现以假乱真的操作。但是该插件在移动端会有很多很多的问题,例如:
(1)在ios系统生成的图片有问题,是一个白色的图片块
(2)在ios系统下生成的图片会有偏移
(3)图片生成的太慢,性能不友好。
。。。
所以思绪良久,还是自己用canvas老老实实的去画吧。
2、使用canvas画图
首先我们需要创建一个画布,此处不用多说,各位巨佬应该都司空见惯了。
其次我们来绘制第一张图片,也就是二维码后面的背景图

let imageBg = new Image();
imageBg.crossOrigin = 'Anonymous'; //解决在画布中图片跨域的问题
imageBg.src = '背景图片的src地址';

然后当这个背景图片创建好了之后再去创建这个二维码图片就可以了,简单操作

imageBg.onload = function() {
  context.drawImage(imageBg, 0, 0, 背景图片的宽, 背景图片的高);
  let codeImg = new Image();
  codeImg.crossOrigin = 'Anonymous'; 
  codeImg.src = '二维码图片的src地址';
  codeImg.onload = function() {
    context.drawImage(codeImg, x坐标, y坐标, 二维码图片的宽, 二维码图片的高);
    此处省略1000行。。。
  }
}

根据这种常规逻辑就可以很快的去实现需求了,但是也不妨遇到一点小坑,在我实现快乐的路上多了点阻碍。
坑点1:canvas.toDataURL方法在ios系统上面失效,运行失败的问题
这样子使用canvas画图会有一个很神奇的问题,就是在ios系统下面这个canvas.toDataURL会抛错
Uncaught DOMException: Failed to execute ‘toDataURL’ on ‘HTMLCanvasElement’: Tainted canvases may not be exported : 大致的意思就是画布被污染

为此我也是去查了文档:
意思就是如果说不加crossorigin属性,但是canvas中使用了其它来源的图片,那么画图就会被污染,toDataURL方法就会抛错,但是纳闷了,我最开始是加了这个属性的,为啥还是会报错呢?
仔细看了一下代码,我最开始是这么加的:

let imageBg = new Image();
imageBg.src = '背景图片的src地址';
imageBg.crossOrigin = 'Anonymous'; //解决在画布中图片跨域的问题

后来发现了坑点所在:
crossOrigin属性必须在src属性之前赋值
crossOrigin属性必须在src属性之前赋值
crossOrigin属性必须在src属性之前赋值

尽管没有找到准确的文档明确指定crossOrigin属性必须在src属性之前赋值,但是要适配IOS确实要这么做。
坑点2:画出来的图片模糊不清晰
按照正常操作的canvas画出来的图片发现会比原图模糊一点:
在网上查找了资料发现原因如下:
canvas 绘图时,会从两个物理像素的中间位置开始绘制并向两边扩散 0.5 个物理像素。当设备像素比为 1 时,一个 1px 的线条实际上占据了两个物理像素(每个像素实际上只占一半),由于不存在 0.5 个像素,所以这两个像素本来不应该被绘制的部分也被绘制了,于是 1 物理像素的线条变成了 2 物理像素,视觉上就造成了模糊
文章链接:https://zhuanlan.zhihu.com/p/31426945

解决办法:

//获取设备的像素比
const getPixelRatio = function (context) {
    let backingStore = context.backingStorePixelRatio ||
        context.webkitBackingStorePixelRatio ||
        context.mozBackingStorePixelRatio ||
        context.msBackingStorePixelRatio ||
        context.oBackingStorePixelRatio ||
        context.backingStorePixelRatio || 1;
    return (window.devicePixelRatio || 1) / backingStore;
};
var context = canvas.getContext("2d");
let ratio = getPixelRatio(context);
// 将canvas的宽高乘上这个像素比
canvas.width = canvas.width * ratio; 
canvas.height = canvas.height * ratio;
// 原理就是将 canvas 的高和宽分别乘以 ratio 将其放大,然后又用 CSS 将高和宽限制成初始的大小 
// 这样子画出来的图片就清晰明了

坑点3:如何准确的将二维码画在指定的位置
其实这儿可以根据ui的设计图的标尺图去设置二维码的位置,例如下图:
在这里插入图片描述

从这个图中你可以准确的计算出,这个二维码在整个图片的x坐标,y坐标
然后在使用context.drawImage(image,x,y,width,height)方法的时候,你就可以根据上面的 x坐标 除以 图片的宽度来计算出二维码图片的横坐标的位置比,然后在根据当前图片的宽高去计算出准确的位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值