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

React-quill编辑器含Base64图片内容转PDF问题求助

解决React-Quill内容(含Base64图片)转PDF的问题

方法一:用html2canvas + jsPDF(简单易实现)

这个方法直接把渲染后的HTML转成画布,再生成PDF,能完整保留原内容的排版和图片显示效果。

步骤:

  • 先安装依赖:
npm install html2canvas jspdf
  • 在React组件中实现:
    把React-Quill的内容渲染到一个可引用的隐藏DOM容器,再通过画布转换生成PDF:
import React, { useRef } from 'react';
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';

const EditorToPDF = () => {
  const contentRef = useRef(null);
  // 从React-Quill获取的富文本内容
  const quillContent = '<p>sdfghj<img src="data:image/jpeg;base64,/9j/4AAQ…r5izLn+Jucfh7Vo6p/r7j6j+VZl595P97/CgD//2Q=="></p>';

  const generatePDF = async () => {
    // 将DOM内容转成画布,scale参数提升清晰度
    const canvas = await html2canvas(contentRef.current, {
      useCORS: true,
      scale: 2
    });

    // 把画布转成图片数据
    const imgData = canvas.toDataURL('image/png');
    // 初始化PDF实例,设置A4纵向
    const pdf = new jsPDF('p', 'mm', 'a4');
    const pageWidth = pdf.internal.pageSize.getWidth();
    const pageHeight = pdf.internal.pageSize.getHeight();
    // 计算图片适配页面的尺寸
    const imgWidth = pageWidth;
    const imgHeight = (canvas.height * imgWidth) / canvas.width;

    // 处理长内容分页
    let heightLeft = imgHeight;
    let position = 0;

    pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
    heightLeft -= pageHeight;

    while (heightLeft >= 0) {
      position = heightLeft - imgHeight;
      pdf.addPage();
      pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
      heightLeft -= pageHeight;
    }

    // 保存PDF文件
    pdf.save('editor-content.pdf');
  };

  return (
    <div>
      {/* 隐藏的内容容器,仅用于生成画布 */}
      <div 
        ref={contentRef} 
        style={{ position: 'absolute', top: -9999, left: -9999 }}
        dangerouslySetInnerHTML={{ __html: quillContent }}
      />
      <button onClick={generatePDF}>生成PDF</button>
    </div>
  );
};

export default EditorToPDF;

方法二:手动解析HTML内容,逐个添加到jsPDF(更灵活)

如果需要自定义排版,可以直接解析React-Quill的HTML字符串,提取文本和图片后手动添加到PDF中。

步骤:

  1. 解析HTML提取元素,用DOMParser处理富文本字符串:
const parser = new DOMParser();
const doc = parser.parseFromString(quillContent, 'text/html');
const nodes = doc.body.childNodes; // 获取所有子元素节点
  1. 遍历元素添加到PDF:
import jsPDF from 'jspdf';

const generatePDF = () => {
  const pdf = new jsPDF('p', 'mm', 'a4');
  let yPosition = 10; // 初始Y轴坐标
  const pageWidth = pdf.internal.pageSize.getWidth();
  const margin = 10; // 页面边距

  const parser = new DOMParser();
  const doc = parser.parseFromString(quillContent, 'text/html');
  const nodes = doc.body.childNodes;

  nodes.forEach(node => {
    // 处理文本节点
    if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
      pdf.setFontSize(12);
      pdf.text(node.textContent.trim(), margin, yPosition);
      yPosition += 10; // 行间距
    }
    // 处理图片节点
    else if (node.tagName === 'IMG') {
      // 去除Base64前缀,只保留编码部分
      const base64Data = node.src.replace(/^data:image\/jpeg;base64,/, '');
      const imgProps = pdf.getImageProperties(base64Data);
      // 计算图片适配页面的尺寸
      const imgWidth = pageWidth - 2 * margin;
      const imgHeight = (imgProps.height * imgWidth) / imgProps.width;

      // 检查是否需要分页
      if (yPosition + imgHeight > pdf.internal.pageSize.getHeight() - margin) {
        pdf.addPage();
        yPosition = margin;
      }

      pdf.addImage(base64Data, 'JPEG', margin, yPosition, imgWidth, imgHeight);
      yPosition += imgHeight + 10; // 图片下方留间距
    }
    // 处理段落元素(可扩展处理其他标签)
    else if (node.tagName === 'P') {
      const text = node.textContent.trim();
      if (text) {
        pdf.setFontSize(12);
        pdf.text(text, margin, yPosition);
        yPosition += 10;
      }
    }
  });

  pdf.save('editor-content.pdf');
};

你之前用jsPDF插入图片空白的常见原因

  • 未正确去除Base64前缀:jsPDF的addImage无法识别带data:image/jpeg;base64,前缀的字符串,需只保留编码部分。
  • 图片尺寸超出页面:图片宽度超过PDF页面宽度时,会被挤出可视区域,导致显示空白。
  • 异步处理问题:如果未等图片解析完成就生成PDF,也会出现空白情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 17:25:26