希望有人能帮我解决这个问题:
目标是将内联 SVG 保存为 PNG 图像。
问题是所说的 SVG 有
foreignObject
元素包含 webfont 图标(来自 Fontawesome 以及使用 Icomoon 创建的自定义图标)。
要将 SVG 导出为 PNG,我使用了 将内联 SVG 保存为 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'
}
}
不确定您从另一个答案中遵循的方法。 我之前使用过 saveSvgAsPng npm 包,它的效果很好。
npm install save-svg-as-png
saveSvgAsPng(document.getElementById("IdOfHTMLDiv"), "ImageName.png");
您也可以导出为
svgAsDataUri
或svgAsPngUri
要添加字体,您可以使用像
这样的选项const imageOptions = {
fonts: [
{
url: 'https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu72xKKTU1Kvnz.woff2',
format: 'application/font-woff2',
text: "@font-face {font-family: 'Roboto'; font-style: normal; font-weight: 400; src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu72xKKTU1Kvnz.woff2) format('woff2'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}",
},
{
url: 'https://fonts.gstatic.com/s/sharetechmono/v9/J7aHnp1uDWRBEqV98dVQztYldFcLowEFA87Heg.woff2',
format: 'application/font-woff2',
text: "@font-face {font-family: 'Share Tech Mono'; font-style: normal; font-weight: 400; src: local('Share Tech Mono'), local('ShareTechMono-Regular'), url(https://fonts.gstatic.com/s/sharetechmono/v9/J7aHnp1uDWRBEqV98dVQztYldFcLowEFA87Heg.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }",
}
],
};
svgAsPngUri(document.getElementById("diagram"), imageOptions).then(uri => ...)
参考Github页面了解更多详情
使用这个没有得到完整的图像;- saveSvgAsPng(document.getElementById("IdOfHTMLDiv"), "ImageName.png");
请帮忙