图片导出

122 阅读1分钟

base64格式: data:image/png;base64,adfsdf...一堆字符

普通小图直接通过image和a标签处理就可以了:

const dataURL = ...  // 非png格式的dataURL,如svg 
const image = new Image()
image.setAttribute('crossOrigin', 'anonymous')
image.onload = function () {
    const canvas = document.createElement('canvas')
    canvas.width = image.width
    canvas.height = image.height
    
    const ctx = canvas.getContext('2d')
    ctx.drawImage(image, 0, 0, image.width, image.height)
    const url = canvas.toDataURL('image/png')
    
    const aLink = document.createElement('a')
    const event = new MouseEvent('click')
    
    a.download = '下载图片'
    a.href = url
    a.dispatchEvent(event)
}
image.src = dataURL

但是当图片很大时,使用上述方法会导出失败,windows上会报错:network error,需要改动一下上面的方法:

function base64ToObjectURL (base64) {
    const arr = base64.split(',')
    const mime = arr[0].replace(/^data:/, '')
    const bstr = arr[1]
    
    let n = bstr.length
    const u8arr = new Uint8Array(n)
    while(n--) {
        u8arr[n] = bstr.charCodeAt(n)
    }
    const blob = new Blob([u8arr], {type: mime})
    const objurl = URL.createObjectURL(blob)
    return objurl
}


const dataURL = ...  // 非png格式的dataURL,如svg 
const image = new Image()
image.setAttribute('crossOrigin', 'anonymous')
image.onload = function () {
    const canvas = document.createElement('canvas')
    canvas.width = image.width
    canvas.height = image.height
    
    const ctx = canvas.getContext('2d')
    ctx.drawImage(image, 0, 0, image.width, image.height)
    const url = canvas.toDataURL('image/png')
    
    const objurl = base64ToObjectURL(url)
    
    const aLink = document.createElement('a')
    const event = new MouseEvent('click')
    
    a.download = '下载图片'
    a.href = objurl
    a.dispatchEvent(event)
    
    URL.revokeObjectURL(objurl)
    a.removeAttribute('href')
}
image.src = dataURL

关于html导出为图片,可以看这篇文章: www.zhangxinxu.com/study/20170…

需要注意的是:这里的样式是简单样式,如果样式有带上 > :after 等这类选择器或伪类,导出的图片可能会样式有问题或者直接导出失败,这时候需要把样式内联的方式加到节点上再执行导出

部分dom需要给他加上width,否则可能超出容器,导致导出的图片右边部分可能会被截掉

svg子节点的布局,在浏览器展示上需要在svg中。布局在svg外的部分会被截掉,有种overflow:hidden效果

svg导出为图片,主要是借助了XMLSerializer

const cloneNode = canvasDom.cloneNode(true);
const svgDocType = document.implementation.createDocumentType('svg', '-//W3C//DTD SVG 1.1//EN', 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd');
const svgDoc = document.implementation.createDocument('http://www.w3.org/2000/svg', 'svg', svgDocType);
svgDoc.replaceChild(cloneNode, svgDoc.documentElement);
const svgData = new XMLSerializer().serializeToString(svgDoc);
const dataURL = "data:image/svg+xml;charset=utf8," + encodeURIComponent(svgData);