Skip to content
New issue

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

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

Already on GitHub? Sign in 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

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

No branches or pull requests

1 participant