使用自定义图标字体将 SVG 导出为图像

问题描述 投票:0回答:2

希望有人能帮我解决这个问题:

目标是将内联 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中描述的第一个解决方案。

但毕竟我仍然无法让图标显示在导出的图像上,我没有想法......

这是 SVG 的网络版本的样子:

这里是导出版本的样子:

这里是导出代码:

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'
    }
}

SVG 中的字体嵌入如下: 嵌入 SVG 的 Base64 编码字体

javascript typescript svg fonts export
2个回答
0
投票

不确定您从另一个答案中遵循的方法。 我之前使用过 saveSvgAsPng npm 包,它的效果很好。

  1. 安装包
    npm install save-svg-as-png
  1. 通过要导出为图像的元素的 hmtl id 使用它,例如:
    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页面了解更多详情


0
投票

使用这个没有得到完整的图像;- saveSvgAsPng(document.getElementById("IdOfHTMLDiv"), "ImageName.png");

请帮忙

© www.soinside.com 2019 - 2024. All rights reserved.