移动端canvas画图中遇到的坑

前端 专栏收录该内容
19 篇文章 0 订阅

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

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

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坐标 除以 图片的宽度来计算出二维码图片的横坐标的位置比,然后在根据当前图片的宽高去计算出准确的位置。

  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

妄想何方_

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值