指定区域截图的最佳实践方式【Doing】


一、背景

最近,工作项目中需要用到指定区域截图的功能,我们常见的方式有HtmlToCanvas这种方式,但是在实现的过程中,发现由于HtmlToCanvas这种第三方库对于一些样式的支持还不够友好,因此带来了一些新的问题,且这些问题并不很好解决。于是,我决定盘点下截图的所有流行方式。并做下对比,从中选出效果最好的方案来。Come on!

二、解决方案对比

1、HtmlToCanvas

众所周知,HtmlToCanvas这种方案也是属于很常见的方式,目前Git上已经迭代至1.6版本了。但是对于由Element-UI库的组件去截图,会有一些棘手的问题。

(1)在新的生成截图的效果中,类型为textarea的Input控件,会出现不支持折行,多行数据只显示一行的问题,超出区域的数据不能被显示的问题。

(2)在新的生成截图的效果中,Select控件,会出现数据偏移,行高显示异常问题。

(3)在新的生成截图的效果中,Data-Picker控件,会出现数据偏移,行高显示异常问题。

(4)在新的生成截图的效果中,类型为Number的Input控件,会出现数据偏移,行高显示异常问题。

2、DomToImage

3、Puppeteer

4、调用浏览器/系统自带的截图方法

三、具体实现方案细节

1、HtmlToCanvas的实现

/*
 * @Description: Html生成Img工具
 * @Date: 2022-05-24 17:08:18
 * @FilePath: src/utils/htmlToImg.js
*/
import html2Canvas from 'html2canvas';

/**
 * @description base64转图片文件
 * @param {String} dataurl 图片数据(base64格式)
 * @param {String} type 文件类型
 * @return {File} File 图片二进制流
 */
const base64ImgtoFile = function(dataurl, type) {
    let binary = atob(dataurl.split(',')[1]);
    let array = [];
    for (let i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], { type: type });
}

/**
 * @description 根据Dom区域生成图片
 * @param {String} ref Dom区域ref
 * @param {String} name 图片名称
 * @return {File} File 图片文件
 */
export default {
    install(Vue) {
        Vue.prototype.createImg = async function (dom) {
            return await html2Canvas(dom, {
                useCORS: true,
                allowTaint: false,
                logging: false,
                letterRendering: true
            }).then(canvas => {
                this.posterImg = canvas.toDataURL('image/png');
                return base64ImgtoFile(this.posterImg, 'image/jpeg');
            })
        }
    }
}

2、DomToImage的实现

/*
 * @Description: Html生成Img工具
 * @Date: 2022-08-01 17:24:38
 * @FilePath: src/utils/domToImg.js
*/

import domToImage from 'dom-to-image';

/**
 * @description base64转图片文件
 * @param {String} dataurl 图片数据(base64格式)
 * @param {String} type 文件类型
 * @return {File} File 图片二进制流
 */
const base64ImgtoFile = function(dataurl, type) {
    let binary = atob(dataurl.split(',')[1]);
    let array = [];
    for (let i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], { type: type });
}

/**
 * @description 根据Dom区域生成图片
 * @return {File} File 图片文件
 */
export default {
    install(Vue) {
        Vue.prototype.screenShot = async function (dom) {
            return await domToImage
                .toPng(dom, {bgcolor: '#fff'})
                .then((dataUrl) => {
                    //输出图片的Base64, dataUrl
                    return base64ImgtoFile(dataUrl, 'image/png');
                })
                .catch(function (error) {
                    console.error('oops, something went wrong!', error)
                })
        }
    }
}

声明:Xuhao's Blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 指定区域截图的最佳实践方式【Doing】


Carpe Diem and Do what I like