前端使用html2canvas生成图片经验总结

前言

主要是总结一下html2canvas生成图片的基础用法,以及自己在使用html2canvas过程中踩过的坑和相应的解决思路

背景

近段时间接手一个项目,需要向设备下发某一个图片,为了该图片可以实时更改,而且为了节省资源,减少接口的请求,所以不适合通过后端接到参数再生成图片,需要前端直接生成图片传给后端,这样图片实时更改也完全可以在前端完成。

选择html2canvas的原因

在前端直接生成图片的话,首先必定是想到了Canvas画图,但是通过Canvas原生API来生成图片又比较繁琐,预研消耗的时间也比较长,所以就想到直接只用开源库,利用html2canvas来生成图片,这样节省了自己很多的开发成本,而且使用这种开源库,也不需要我去担心后期的维护或者当中可能出现的风险,因为html2canvas相对来说已经算是成熟稳定的开源库了。总的来说,我们对于生成图片的需求没那么复杂,同时为了节省开发的时间,这是我选择html2canvas的原因。

html2canvas的基本介绍

原理

在我看来,html2canvas的效果就好像对页面中的某一模块进行了截图处理,截取的图片就是前端生成的图片。可是在我看了html2canvas官方文档之后,其实html2canvas看似是截图,其实真正的工作原理是通过读取网页上的目标DOM节点的信息去绘制一个canvas,然后再通过调用的canvastoDataURL()方法生成<img>图片

基础用法

安装

npm i html2canvas

导入引用

import html2canvas from 'html2canvas'

使用

首先是HTML部分

因为html2canvas就是根据DOM节点来生成canvas的,所以这段html代码就是我们需要绘制的DOM节点,该html在页面中展示的效果就是即将生成的图片效果,所以看起来会像截图一样,因为使用了Vue,所以这里用ref来绑定该DOM

重点是JavaScript部分,这里我重新编写一遍代码

html2canvas(this.$refs.xxxx. {useCORS: true, // 使用跨域backgroundColor: null // 没有背景色
}).then((canvas) => {let url = canvas.toDataURL('image/png');console.log(url);
})

在这段代码中,首先向html2canvas传入我们需要生成图片的DOM节点,通过ref来绑定该DOM,等到html2canvas通过该DOM节点的信息生成canvas后,再调用canvas.toDataURL('image/png')方法,image/png是要生成的图片格式为png,然后该方法会返回一个图片的base64,下面是我生成的图片效果

踩过的坑

接下来我主要列举一下在使用html2canvas过程中踩过的坑,以及我的解决方案

问题一:图片渲染的不完整

因为html2canvas生成图片是需要获取选定的DOM的,但我当前的页面中,没有地方可去展示这块DOM,所以一开始我想要动态的去渲染该DOM,也就是等到我需要生成图片的时候,我才去生成DOM然后再传给html2canvas,但是这就遇到了一个比较严重的问题,就是图片渲染的不完整,从我上面的html代码中可以得知,我需要渲染的图片中,也有两张图片,因为DOM的渲染也需要时间,并且html2canvas生成图片是一个异步的过程,这就导致在生成图片时,其实获取的DOM信息并不完整,只能够获取到文字元素的信息,获取不到图片的信息。就大抵是下图的一个效果,只有文字。

解决方案

我这个方案其实有一些懒省事,我放弃了动态生成DOM的想法,转而一开始就将我需要的DOM给渲染在页面中,只不过因为页面中没有可以展示它的位置,所以我将该DOM元素用定位的方式隐藏在超出页面很多的角落,因为定位脱离的元素文档流,所以也不用担心会因此改变页面的结构,但是这种提前渲染我总觉得也是一种资源消耗,所以问题是解决了,但是如果大家有什么更好的解决方法,可以评论给我。

问题二:图片涉及跨域问题导致无法渲染

这个问题产生的原因依旧还是跟DOM中存在的img标签相关,从上面图片生成的最终效果,大家可以知道,我最好需要的图片,是有一个底图背景和其他图片的,而跨域的图片虽然可以被canvas读取,但是这也会导致canvas被污染,进而导致canvas无法导出img标签可用的图片数据。

解决方案一:加入allowTaint属性设置为true,加入useCORS属性设置为true(失败)

加入这两个属性之后,本来以为可以完成跨域生成图片,可是结果是html2canvas依然会报图片跨域的错误,因为这个错误,生成的图片就是一片空白,原因是因为html2canvas需要我们先提供一段DOM节点,然后它再读取并解析这一段DOM节点生成canvas对象。如果DOM节点中已经使用了标签的话,它也会解析这个标签的src属性,然后重新创建一个Image对象,给它添加crossOrigin="anonymous"属性后尝试以跨域的方式重新读取图片数据。需要注意的是,一般CDN上的图片都是带有缓存响应头并且会在浏览器端缓存的,而且缓存的不仅仅是图片数据,还有HTTP响应头。所以问题的根本原因我们就找到了,当html2canvas尝试以跨域的方式去读取图片数据时,它读取到的是浏览器的缓存数据,而且因为我们没有给DOM节点中的标签添加crossorigin="anonymous"属性,所以缓存数据是不带Access-Control-Allow-Origin响应头的,进而导致html2canvas库读取到的图片数据污染了生成的canvas对象,最终致使canvas导出数据报错。

解决方案二:给DOM中已存在img标签都加上crossorigin="anonymous"属性(失败)

从上面的原因我们可以得知,需要在DOM中已存在得每个img标签都加上crossorigin="anonymous"属性,果不其然,解决了html2canvas所报出得跨域错误,但由于当前页面的DOM信息中,两个图片是我之前上传到后端服务器保存的,然后后端传给我服务器自己的图片url后,因为设置了跨域,所以会导致读取服务器图片url失败,所以这个方法最终也是不可取。

解决方案三:将图片转为base64格式再去生成图片(成功)

这个方法比较简单粗暴,将图片直接转为base64,也不存在图片跨域的问题,可以直接通过html2canvas生成该图片
下面是转base64方式的方法
先根据服务器地址下载图片获取图片的二进制流,然后将二进制流转为base64

问题三:生成的图片模糊

其实这是最小的一个问题,但也是导致上面两个问题的导火索之一,在生成图片的时候,一开始并没有用img来作为底图,而是使用了background-image属性,这就导致了html2canvas生成的图片有点模糊,一开始我也尝试了放大图片之后再生成,然后用的时候在缩小,但是感觉依旧是模糊,有种画质不好的感觉,在看完文档之后也了解到它的图片生成和设备的分辨率也有关,这就让人比较无奈

解决方案

关于解决其实是无意中想要用img去替代background-image属性,但是替换之后,哦豁,发现效果出奇的好,大家也可以看到我最后的效果图,还是蛮清晰的。可能跟html2canvas的底层逻辑有关吧,关于这个问题我没有研究的很深,毕竟是解决了嘛

总结

以上就是我这次使用了html2canvas在前端直接生成图片的一些经验总结,遇见问题还是不要慌,除了官方文档和博客,也可以稍微进行一些天马行空的尝试,不消耗大量时间就也不亏嘛,在记录自己经验的同时,也希望能够对大家有所帮助,一起共同进步。

前端使用html2canvas生成图片踩坑相关推荐

  1. html2canvas的踩坑之路

    前言 早有耳闻这个html2canvas比较坑,但无奈于产品需求的压迫,必须实现html转图片的功能,自此走上了填坑之路,好在最后的效果还算令人满意,这才没有误了产品上线周期. html2canvas ...

  2. 前端使用html2canvas生成图片

    项目场景是完成测评试题,生成学生测评报告,部署在移动端H5页面, 本文记录vue中使用html2canvas生成图片. html2canvas官方网站 1基础使用 1.1 安装html2canvas ...

  3. html2canvas (踩坑) 网络图片显示不出来生成图片只有一半或者空白文字显示不出来问题处理

    这里只提供解决思路,代码就不粘贴出来了 图片显示不出来 就像大多数人说的一样,HTML中的图片产生了跨域,可以将网络图片转为base64后修改img 的src属性值,添加图片允许跨域的属性.调用htm ...

  4. toFixed踩坑记

    每天上一当,当当不一样.前端菜鸡的踩坑日记! tofixed()是采用的一种四舍六入五成双的'银行家算法',并不是我们以为的那种四舍五入 银行家算法: 对于位数很多的近似数,当有效位数确定后,其后面多 ...

  5. html2canvas图片的文字偏移,html2canvas在Vue项目踩坑-生成图片偏移不完整

    背景 最近做一个Vue项目需求是用户长按保存图片,页面的数据是根据不同id动态生成的,页面渲染完生成内容图片让用户长按保存的时候,把整个页面都保存起来. 在项目遇到的坑是图片能生成,可是生成的图片总是 ...

  6. html2canvas在Vue项目踩坑-生成图片偏移不完整

    背景 最近做一个Vue项目需求是用户长按保存图片,页面的数据是根据不同id动态生成的,页面渲染完生成内容图片让用户长按保存的时候,把整个页面都保存起来. 在项目遇到的坑是图片能生成,可是生成的图片总是 ...

  7. 移动端 html2canvas 踩坑记录

    背景 最近在做的微信 html5 项目有个需求:页面包含 一张大的背景图片 + 一个用户的链接二维码图片 拼成一张图片,让用户长按保存的时候,可以把整个页面都保存起来,而不是只保存二维码. 思考 1. ...

  8. html2canvas跨域踩坑日常

    这两天接到公司的指令做海报图分享 然后尝试使用html2canvas+uview+uniapp进行编写 踩坑如下 html2canvas跨域问题 我司使用的是oss云存储,起初发生跨域以为是本地原因导 ...

  9. 前端静态服务踩坑实践

    前言 随着前端项目的增大,越来越多时候会把动静态资源进行分离部署,对于分离部署时常常涉及到代理转发的问题,专网项目主要使用 nginx + docker + k8s的部署方式,本文主要分享一些相关项目 ...

最新文章

  1. 支持向量机背后的数学原理!
  2. Navicat Premium
  3. GPU硬件结构和程序具体参数设置
  4. C#正在被人用来做什么?--在CSDN上引发小讨论的帖子
  5. java 局部内部类常用么_Java中的内部类
  6. 安装mysql 5.1 详细步骤
  7. How to Calibrate Battery And Charge Battery To Max
  8. BCD与ASCII码互转-C语言实现
  9. salesforce 零基础开发入门学习(十四)salesforce中工厂模式的运用
  10. springBoot入门第一章springBoot第一个程序
  11. Unity AnimatorController 混合树 状态机 骨骼
  12. Myeclipse6.5中安装maven
  13. go语言中错误处理方式
  14. java 8 64位官方下载_Java 8下载 Java 8.0U181官方正式版(32位/64位) 下载-脚本之家
  15. 通过poi读取ppt元素demo
  16. 定义一个list对象数组 java_javascript定义一个list
  17. QNX系统开启telnet远程登录
  18. 像素值/DN值/数字量化值
  19. 不用安装Wincap程序实现ARP广播包的发送和接收
  20. 公司内网安装dns,然后把域名ning.com直接指向ingress-nginx的ip

热门文章

  1. 排错实战——解决c++编译错误:error C2059: illegal token on right side of '::'
  2. rtmp2flv rtmp直播转httpflv工具
  3. Navicat Premium 12 免安装版
  4. c语言写一个进出货管理,[源码和文档分享]基于C语言实现的超市管理系统
  5. Python:类与结构体
  6. python根据url下载数据_利用Python如何实现根据URL地址下载并保存文件至对应目录...
  7. vivo手机计算机恢复出厂设置,vivo手机系统恢复出厂设置里面清除所有数据
  8. 有哪些好用的App云测试平台?
  9. PGSQL(学习与操作)
  10. win7 mac 时间不一致