You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular(Ionic/Cordova) iOS端SVG转图片/PDF节点丢失问题求方案

iOS端SVG转图片/PDF问题的解决方案(Angular/Ionic/Cordova)

问题根源

  • iOS WebKit内核(Safari及Cordova WebView)对foreignObject的Canvas渲染支持有限,异步加载的Base64图片常未完成就触发绘制
  • SVG中引用的本地字体在Canvas绘制时可能未加载完毕
  • Cordova iOS WebView存在资源加载时序问题,导致图片渲染不完整

方案一:确保资源加载完成后再绘制Canvas

步骤1:预加载所有Base64图片

遍历SVG字符串中的Base64图片资源,创建Image对象预加载,确保所有图片加载完成后再执行绘制。

async preloadSvgImages(svgString: string): Promise<void> {
  const imgRegex = /background-image: url\(&quot;data:image\/png;base64,([^&]+)&quot;\)/g;
  let match;
  const promises: Promise<void>[] = [];

  while ((match = imgRegex.exec(svgString)) !== null) {
    const base64Data = match[1].replace(';', ''); // 修复原始SVG中的多余分号
    const img = new Image();
    promises.push(new Promise((resolve, reject) => {
      img.onload = () => resolve();
      img.onerror = reject;
      img.src = `data:image/png;base64,${base64Data}`;
    }));
  }

  await Promise.all(promises);
}

步骤2:修复字体引用问题

将SVG中@font-face的本地字体替换为Base64嵌入,避免iOS WebKit无法加载本地字体:

@font-face {
  font-family: mdzRoboto;
  src: url(data:font/truetype;base64,【你的字体Base64内容】) format("truetype");
  font-weight: 400;
  font-style: normal;
}

步骤3:延迟Canvas绘制

预加载完成后,用requestAnimationFrame确保浏览器完成资源渲染再绘制:

async svgToImage(svgString: string): Promise<string> {
  await this.preloadSvgImages(svgString);

  return new Promise((resolve) => {
    requestAnimationFrame(async () => {
      const svgBlob = new Blob([svgString], { type: 'image/svg+xml' });
      const svgUrl = URL.createObjectURL(svgBlob);
      const img = new Image();

      img.onload = () => {
        const canvas = document.createElement('canvas');
        canvas.width = img.width;
        canvas.height = img.height;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);
        const imgDataUrl = canvas.toDataURL('image/png');
        URL.revokeObjectURL(svgUrl);
        resolve(imgDataUrl);
      };

      img.src = svgUrl;
    });
  });
}

方案二:绕过Canvas,直接转Blob导出

转图片并保存到本地

async svgToImageBlob(svgString: string): Promise<Blob> {
  const svgBlob = new Blob([svgString], { type: 'image/svg+xml' });
  const svgUrl = URL.createObjectURL(svgBlob);
  
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => {
      const canvas = document.createElement('canvas');
      canvas.width = img.width;
      canvas.height = img.height;
      const ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0);
      canvas.toBlob((blob) => {
        URL.revokeObjectURL(svgUrl);
        resolve(blob);
      }, 'image/png');
    };
    img.onerror = reject;
    img.src = svgUrl;
  });
}

// 配合Cordova File插件保存
async saveImageToLocal(blob: Blob, fileName: string) {
  const fileEntry = await this.file.writeFile(this.file.dataDirectory, fileName, blob, { replace: true });
  return fileEntry.nativeURL;
}

转PDF(使用jsPDF)

先安装依赖:npm install jspdf

import jsPDF from 'jspdf';

async svgToPdf(svgString: string): Promise<Blob> {
  const svgBlob = new Blob([svgString], { type: 'image/svg+xml' });
  const svgUrl = URL.createObjectURL(svgBlob);
  
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => {
      const pdf = new jsPDF('p', 'px', [img.width, img.height]);
      pdf.addImage(img, 'PNG', 0, 0, img.width, img.height);
      const pdfBlob = pdf.output('blob');
      URL.revokeObjectURL(svgUrl);
      resolve(pdfBlob);
    };
    img.onerror = reject;
    img.src = svgUrl;
  });
}

关键注意事项

  • 确保SVG中foreignObject的xmlns属性为http://www.w3.org/1999/xhtml
  • 移除SVG中-webkit-transform,替换为SVG原生transform属性
  • Cordova项目需确保Content-Security-Policy允许data URI加载(默认允许,自定义CSP需检查)

内容的提问来源于stack exchange,提问作者VinceSanto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 23:45:05