当前位置: 首页 > news >正文

DOM生成图片原理

工作原理

使用svg的一个特性,允许在<foreignobject>标签中包含任意的html内容。(主要是 XMLSerializer | MDN这个apidom转为svg) 所以,为了渲染那个dom节点,你需要采取以下步骤:

  1. 递归 clone 原始的 dom 节点
  2. 获取 节点以及子节点 上的 computed style,并将这些样式添加进新建的style标签中(不要忘记了clone 伪元素的样式)
  3. 嵌入网页字体
  • 找到所有的@font-face
  • 解析URL资源,并下载对应的资源
  • base64编码和内联资源 作为 data: URLS引用
  • 把上面处理完的css rules全部都放进<style>中,并把标签加入到clone的节点中去
  1. 内嵌图片(都转成dataUrl)
  • 内联图片src 的url 进 <img>元素
  • 背景图片 使用 background css 属性,类似fonts的使用方式
  1. 序列化 clone 的 dom 节点 为 svg
  2. 将xml包装到<foreignobject>标签中,放入svg中,然后将其作为data: url
  3. 将png内容或原始数据作为uint8array获取,使用svg作为源创建一个img标签,并将其渲染到新创建的canvas上,然后把canvas转为base64
  4. 完成

1. 复制 DOM 并序列化

const cloneNode = document.body.cloneNode(true);
const xmlSerializer = new XMLSerializer();
const html = xmlSerializer.serializeToString(cloneNode);

2. 嵌入 svg foreignObject

const svg = `
  <svg
    xmlns='http://www.w3.org/2000/svg'
    width='${document.body.clientWidth}'
    height='${document.body.clientHeight}'
  >
    <foreignObject
      x='0'
      y='0'
      width='100%'
      height='100%'
    >
      ${html}
    </foreignObject>
  </svg>
`;

3.通过 canvas 生成图片

const canvas = document.createElement('canvas');
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = () => {
  ctx.drawImage(img, 0, 0);
  canvas.toBlob((blob) => {
    const blobURL = URL.createObjectURL(blob);
    window.open(blobURL);
    URL.revokeObjectURL(blobURL);
  });
};
img.src = `data:image/svg+xml;charset=utf-8,${svg}`;

问题:图片内容无样式

svg 以字符串的形式通过 img src data 加载,不与当前页面共享样式。

市面上的截图插件 html2canvas、dom-to-image 都是通过内联样式的方式解决此问题。 深度遍历每个源 DOM 元素,每个 DOM 元素通过 window.getComputedStyle 方法当前元素的所有样式属性和值。 找到相应的克隆 DOM 元素,通过 getPropertyValue 方法和 setProperty 方法重新赋值。

问题:图片内容字体丢失

跟图片内容样式丢失原因一样,字体也需要嵌入 svg。 因为不与当前页面共享资源,字体资源引用不能使用 URL 形式,需要转换成 base64 格式。

const response = await fetch(url, { headers: { responseType: 'blob' } });
const blob = await response.blob();
const fileReader = new FileReader();
fileReader.onload = () => {
  const b64 = fileReader.result;
};
fileReader.readAsDataURL(blob);

svgStyle 添加字体声明。

svgStyle += `
	@font-face {
		font-family: "${name}";
		src: local("${name}"), url("${b64}");
	}
`;

参考链接

  • ​​​​​​CSSStyleDeclaration.setProperty() - Web API 接口 | MDN
  • dom-to-image
  • XML DOM - XMLSerializer 对象

相关文章:

  • 笔记本怎么录制屏幕?只需2分钟,快速学会
  • Conv2Former: A Simple Transformer-Style ConvNet for Visual Recognition
  • 【C++11】可变参数和lambda表达式
  • 基于鸽群算法改进的DELM预测 -附代码
  • uni-app 微信支付-小程序、APP、IOS
  • 等保2.0参与医院网络安全管理的重要性
  • 以数据赋能业务,qlik为企业搭建透明绩效管理平台
  • [ Linux ] 死锁以及如何避免死锁
  • JavaScript时间格式化插件,返回指定字符串
  • 多播网络(Multicast)应用权限
  • 使用mosquitto部署MQTT服务
  • Zookeeper 4 Zookeeper JavaAPI 操作 4.7 Curator API 常用操作【Watch 事件监听】
  • 【发表案例】计算机科学类SCI,仅1个月零6天录用,涵盖软件、信息、数据云计算、网络、建模等研究方向
  • 【JavaScript】15_debug,立即执行函数 与 严格模式
  • 智能制造数字化转型难点有哪些?
  • 【UE4 第一人称射击游戏】06-设置动画角色2
  • U-net
  • pytest-需要模块相应的库
  • VSCode连GitHub的代理服务器配置和获取历史版本命令
  • 笔试训练(4)