Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

SVG <image> 元素使用外部 URL 时无法在截图库中渲染 #122

Open
linyucion opened this issue Dec 4, 2024 · 1 comment
Open

Comments

@linyucion
Copy link

Steps To Reproduce

Playground for https://play.vuejs.org

Error Message & Stack Trace

<!-- Provide a log message if relevant -->

Your Environment

  • modern-screenshot: [e.g. 4.5.5]
  • Browser: [e.g. chrome 131.0.6778.109]
@linyucion
Copy link
Author

经检查,chrome浏览器在版本131.0.6778.70开始会出现这个问题,在此之前的版本上是正常的;
调试源码4.5.5源码后发现,
src\converts\dom-to-canvas.ts line 14
const dataUrl = await svgToDataUrl(svg, context.isEnable('removeControlCharacter'))

该行代码在出现问题的浏览器版本的浏览器中,返回的svg的dataURL中,image的外部链接图片已经为空;

下面是借助GPT实现的修复代码,供作者大佬参考下
src\utils.ts

export async function svgToDataUrl(svg: SVGElement, removeControlCharacter: boolean): Promise<string> {
  // 1. 获取所有 <image> 标签
  const images = Array.from(svg.querySelectorAll('image'))

  // 2. 将所有图片处理为 Base64
  await Promise.all(
    images.map(async (img) => {
      const href = img.getAttribute('xlink:href')
      if (href && !href.startsWith('data:')) {
        const base64Data = await fetchImageAsBase64(href) // 等待 Base64 转换完成
        img.setAttribute('xlink:href', base64Data) // 更新 <image> 的 xlink:href 属性
      }
    }),
  )

  // 3. 序列化 SVG
  let xhtml = new XMLSerializer().serializeToString(svg)

  if (removeControlCharacter) {
    xhtml = xhtml.replace(/[\u0000-\u0008\v\f\u000E-\u001F\uD800-\uDFFF\uFFFE\uFFFF]/gu, '')
  }

  // 4. 返回 Data URL
  return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(xhtml)}`
}

// 辅助函数:将图片加载并转换为 Base64
export async function fetchImageAsBase64(url: string): Promise<string> {
  const response = await fetch(url) // 加载图片
  const blob = await response.blob() // 转换为 Blob 对象
  const reader = new FileReader()

  return new Promise((resolve, reject) => {
    reader.onloadend = () => resolve(reader.result as string) // 加载完成返回 Base64 数据
    reader.onerror = reject // 出现错误时抛出异常
    reader.readAsDataURL(blob) // 将 Blob 转换为 Base64
  })
}

image

src\converts\dom-to-canvas.ts line 14
const dataUrl = await svgToDataUrl(svg, context.isEnable('removeControlCharacter'))
image

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant