【发布时间】:2021-09-05 05:42:00
【问题描述】:
希望有人能帮我解决这个问题:
目标是将内联 SVG 保存为 PNG 图像。
问题在于,上述 SVG 具有包含 webfont 图标的 foreignObject 元素(来自 Fontawesome 以及使用 Icomoon 创建的自定义图标)。
为了将 SVG 导出为 PNG,我使用了 Save inline SVG as JPEG/PNG/SVG 中描述的方法。
为了获得 SVG 的正确视图,我将所有计算的样式复制到 svg 元素的副本中作为内联样式(复制以不污染原始样式)。但是,由于字体图标仅作为 ::before 元素嵌入 HTML 中,并且这些元素不能用作内联样式,因此在导出 SVG 时它们被忽略了。
我的解决方法是将图标字形的 unicode 作为 innerHTML 标记的 i 并让 SVG 像普通文本一样处理它。
这里的问题是导出的图像无法访问包含图标的字体。所以我尝试使用Including fonts when converting SVG to PNG 中描述的解决方法,并将图标字体的base64 编码版本嵌入到svgs defs --> style 标签内。这种方法的第一个问题是我不能直接使用btoa(),因为我添加了图标unicode字符,但为此使用了MDN Web Docs中描述的第一个解决方案。
但在这一切之后,我仍然无法让图标显示在导出的图像上,而且我没有想法......
这是导出的代码:
download(selector: string, name: string): void {
const svg = <HTMLElement>document.querySelector(selector + ' svg')
const svgCopy = svg.cloneNode(true) as HTMLElement
this.computedToInline(svg, svgCopy)
const canvas = <HTMLCanvasElement>document.querySelector('canvas')
canvas.width = svg.getBoundingClientRect().width
canvas.height = svg.getBoundingClientRect().height
const ctx = canvas.getContext('2d')
if (!ctx) return
const data = new XMLSerializer().serializeToString(svgCopy)
const image = new Image()
const encodedData = btoa(unescape(encodeURIComponent(data)))
const url = 'data:image/svg+xml;base64,' + encodedData
image.onload = () => {
ctx.drawImage(image, 0, 0)
window.URL.revokeObjectURL(url)
const imageURI = canvas
.toDataURL('image/png')
.replace('image/png', 'image/octet-stream')
this.triggerDownload(imageURI, name)
}
image.src = url
}
computedToInline(element: HTMLElement, elementCopy: HTMLElement): void {
if (element.hasChildNodes()) {
for (let i = 0; i < element.children.length; i++) {
this.computedToInline(
element.children[i] as HTMLElement,
elementCopy.children[i] as HTMLElement
)
}
}
const computedStyles = getComputedStyle(element)
for (let i = 0; i < computedStyles.length; i++) {
const style = computedStyles[i]
elementCopy.style.setProperty(style, computedStyles.getPropertyValue(style))
}
if (element.classList.contains('icon')) {
elementCopy.style.font = '900 14px "Custom Icon Font"'
// the text ICON is just added for visualisation purpose
elementCopy.innerHTML = 'ICON\ue900'
}
}
【问题讨论】:
标签: javascript typescript svg fonts export