Экспорт SVG как изображения с пользовательским шрифтом значка

Я надеюсь, что кто-то может помочь мне с этой проблемой:

Цель состоит в том, чтобы сохранить встроенный SVG как изображение PNG.

Проблема в том, что указанный SVG имеет foreignObject элементов, содержащих значки веб-шрифтов (из Fontawesome, а также пользовательские, созданные с помощью Icomoon< /а>).

Чтобы экспортировать SVG как PNG, я использовал подход, описанный в Сохранить встроенный SVG как JPEG/ PNG/SVG. Чтобы получить правильный вид SVG, я скопировал все вычисленные стили в копию элемента svg как встроенные стили (скопируйте, чтобы не загрязнять исходный). Но поскольку значки шрифтов встроены в HTML только как элементы ::before и не работают как встроенные стили, они были исключены при экспорте SVG. Мой обходной путь заключался в том, чтобы поместить юникод глифа значка как innerHTML тега i и позволить SVG обрабатывать его как обычный текст.

Проблема заключалась в том, что экспортированное изображение не имело доступа к шрифтам, содержащим значки. Поэтому я попытался использовать обходной путь, описанный в включение шрифтов при преобразовании SVG в PNG и вставьте закодированную в base64 версию иконочного шрифта внутри тегов svgs defs --> style. Первая проблема с этим подходом заключалась в том, что я не мог использовать btoa() напрямую, потому что я добавил символы юникода для значков, но для этого используется первое решение, описанное в Веб-документы MDN.

Но после всего этого я все еще не могу заставить значки отображаться на экспортированном изображении, и у меня нет идей...

Вот как выглядит веб-версия SVG: Встроенный SVG, как он виден внутри веб-приложения

Вот как выглядит экспортированная версия: Экспортированное изображение 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 встроен следующим образом: шрифт в кодировке Base64, встроенный в SVG введите здесь описание изображения


person MarSim    schedule 21.06.2021    source источник


Ответы (1)


Не уверен в подходе, который вы используете из другого ответа. Раньше я использовал пакет saveSvgAsPng npm, он работает как шарм.

  1. Установить пакет
    npm install save-svg-as-png
  1. Используйте его по идентификатору hmtl элемента, который вы хотите экспортировать как изображение, например:
    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.

person Pranav Singh    schedule 22.06.2021