Я надеюсь, что кто-то может помочь мне с этой проблемой:
Цель состоит в том, чтобы сохранить встроенный 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:
Вот как выглядит экспортированная версия:
Вот код для экспорта:
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