html2canvas跨域截图_浏览器端网页截图方案详解

本文深入剖析了 html2canvas 截图插件的实现原理,探讨其在处理 CSS box-shadow 和边框虚线等场景的不足。提出了一种新的思路,利用 SVG 的 标签将 HTML 转化并绘制到 Canvas,以避免精度问题。文章详细阐述了 SVG 转换和渲染的步骤,包括资源内联、脚本处理和大小计算,但指出 SVG 方法也存在浏览器兼容性和图片跨域等问题。
摘要由CSDN通过智能技术生成

简介

剖析流行的截图插件 html2canvas 的实现方案,探索其功能上的一些不足之处及不能正确截取的一些场景,比如不支持 CSS 的 box-shadow 截取情况等。探索一种新的实现方式,能够避免多数目前 html2canvas 不支持的情况,解密其原理,深究 Canvas 绘图的机制。

本篇文章你可以学到:

  1. 纯前端网页截图的基本原理
  2. html2canvas 的核心原理
  3. SVG 内嵌 HTML 的方式
  4. Canvas 渲染 SVG 的方式及各种问题的解决方案

适合人群:前端开发

开篇

平时很多时候,需要把当前页面或者页面某一部分内容保存为图片分享出去,也或者有其他的业务用途,这种在很多的营销场景和裂变的过程都会使用到,那我们要把一个页面的内容转化为图片的这个过程,就是比较需要探讨的了。

首先这种情况,想到的实现方案就是使用 Canvas 来实现,我们探索一下基本实现步骤:

  1. 把需要分享或者记录的内容绘制到 Canvas 上
  2. 把绘制之后的 Canvas 转换为图片

这里需要明确的一点就是,只要把数据绘制到 Canvas 上,这就在 Canvas 画布上形成了被保存在内存中的像素点信息,所以可以直接调用 Canvas 的 API 方法 toDataURL、toBlob,把已经形成的像素信息转化为可以被访问的资源 URI,同时保存在服务器当中。这就很轻松的解决了第二步(把 Canvas 转为图片链接),下面是代码的实现:

fd3be6b0240b52994763c897a66e3b4f.png

在实现了第二步的情况之下,需要关注的就是第一步的内容,怎么把内容绘制到 Canvas 上,我们知道 Canvas 的绘图环境有一个方法是 ctx.drawImage,可以绘制部分元素到 Canvas 上,包含图片元素 Image、svg 元素、视频元素 Video、Canvas 元素、ImageBitmap 数据等,但是对于一般的其他 div 或者列表 li 元素它是不可以被绘制的。

所以,这不是直接调用绘图的 API 就可以办到的,我们就需要思考其他的方法。在一般的实现上,比较常见的就是使用 html2canvas,那么我们先来聊聊 html2canvas 的使用和实现。

html2canvas 的使用及实现

使用

首先看一下 html2cavas 的使用方法:

9aed852bda6bcfb263336cbd05fcfafa.png

调用 html2canvas 方法传入想要截取的 Dom,执行之后,返回一个 Promise,接收到的 Canvas 上,就绘制了我们想要截取的 Dom 元素。到这一步之后,我们再调取 Canvas 转图片的方法,就可以对其做其他的处理。

这里它的 html2canvas 方法还支持第二个选项传入一些用户的配置参数,比如是否启用缓存、整个绘图 Canvas 的宽高值等。

在这个转换的过程,在 html2canvas 的内部,是怎么把 Dom 元素绘制到 Canvas 上的,这是咱们需要思考的问题!

实现

首先咱们先献上一个内部的大致流程图:

88446791dedada0041d81bc26d84d8bf.png

对比着内部的流程图,就可以理一下整体的思路,整体的思路就是遍历目标节点和子节点,收集样式,计算节点本身的层级关系和根据不同的优先级绘制到画布中,下面基于这个思路,咱们深入一下整个过程。

1. 调用 html2canvs 函数,直接返回一个执行函数,这一步没有什么。

2. 在执行函数的内部第一步是构建配置项 defaultOptions,在合并默认配置的过程中,有一个缓存的配置,它会生成处理缓存的方法。

  • 处理缓存类,对于一个页面中的多个不同的地方渲染调用多次的情况做优化,避免同一个资源被多次加载;
  • 缓存类里面控制了所有图片的加载和处理,包括使用 proxy 代理和使用 cors 跨域资源共享这两种情况资源的处理,同时也对 base64 和 blob 这两种形式资源的处理。比如如果渲染 Dom 里面包含一个图片的链接类型是 blob,使用的方式就是如下处理,然后添加到缓存类中,下次使用就不需要再重新请求。

558cf150f40b73e2cdd7e9a6787373d1.png

3. 在上一步生成了默认配置的情况之下,传入需要绘制的目标节点 element 和配置到 DocumentCloner 里面,这个过程会克隆目标节点所在的文档节点 document,同时把目标节点也克隆出来。这个过程中,只是克隆了开发者定义的对应节点样式,并不是结合浏览器渲染生成特定视图最后的样式

2ed6f7578d849b3f0968e396bd0814fe.png

如上这个 .box 的元素节点,定义的样式只有高度,但是在浏览器渲染之下,会对它设置默认的文字样式等等。

4. 基于上一步的情况,就需要把克隆出来的目标节点所在的文档节点 document 进行一次浏览器的渲染,然后在收集最终目标节点的样式。于此,把克隆出来的目标节点的 document 装载到一个 iframe 里面,进行一次渲染,然后就可以获取到经过浏览器视图真实呈现的节点样式。

79e3ccff6774168a00fd90b3db3e9ee9.png

在这个过程中,就可以通过 window.getComputedStyle 这个 API 拿到要克隆的目标节点上所有的样式了(包含自定义和浏览器默认的结合最终的样式)。

5. 目标节点的样式和内容都获取到了之后,就需要把它所承载的数据信息转化为 Canvas 可以使用的数据类型,比如某一个子节点的宽度设置为 50%或者 2rem,在这个过程中,就需要根据父级的宽度把它计算成为像素级别的单位。同时对于每一个节点而言需要绘制的包括了边框、背景、阴影、内容,而对于内容就包含图片、文字、视频等。这个过程就需要对目标节点的所有属性进行解析构造,分析成为可以理解的数据形式。

61589039e10741787e3707c090c25ff6.png

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值