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

如何从src为PDF Blob的iframe中获取修改后的字节数据?

可行方案:替换原生PDF查看器为PDF.js

浏览器原生PDF查看器的iframe/embed是沙箱隔离的,无法直接访问其内部的表单修改数据,这是浏览器安全策略限制,没有绕过的办法。要实现需求,最靠谱的方式是用开源的PDF.js替代原生查看器,它能完全在浏览器端控制PDF文档,轻松获取修改后的表单数据。

核心思路

  1. 保留你现有流程的前3步:用pdf-lib加载模板、填充初始数据、生成字节流
  2. 放弃原生iframe,改用PDF.js渲染填充后的PDF,让用户在PDF.js的界面里修改表单
  3. 点击导出按钮时,通过PDF.js的API获取所有表单字段的当前值
  4. 用pdf-lib重新加载原始模板,填入修改后的数据,扁平化表单并下载

代码示例(关键部分)

首先引入PDF.js(建议本地部署,避免CDN跨域问题):

<script src="path/to/pdf.min.js"></script>
<script src="path/to/pdf.worker.min.js"></script>
<script src="https://unpkg.com/pdf-lib@latest"></script>

初始化PDF查看器并加载填充后的PDF

// 配置PDF.js的worker路径
pdfjsLib.GlobalWorkerOptions.workerSrc = 'path/to/pdf.worker.min.js';

async function initPDFViewer(originalTemplateBytes, initialFormData) {
  // 1. 用pdf-lib填充初始数据,得到预填充的PDF字节流
  const prefilledPdfDoc = await PDFLib.PDFDocument.load(originalTemplateBytes);
  const form = prefilledPdfDoc.getForm();
  Object.keys(initialFormData).forEach(fieldName => {
    const field = form.getField(fieldName);
    if (field) field.setText(initialFormData[fieldName]);
  });
  const prefilledBytes = await prefilledPdfDoc.save();

  // 2. 用PDF.js加载预填充的PDF
  const loadingTask = pdfjsLib.getDocument({ data: prefilledBytes });
  const pdfDoc = await loadingTask.promise;
  
  // 3. 获取表单对象,PDF.js会自动渲染可编辑字段
  const pdfForm = await pdfDoc.getForm();
  // 将pdfDoc和pdfForm存到全局,方便后续导出时用
  window.currentPdfDoc = pdfDoc;
  window.currentPdfForm = pdfForm;

  // 4. 渲染PDF到页面容器(这里用基础渲染,也可以用官方Viewer组件实现完整工具栏)
  const container = document.getElementById('pdf-container');
  const page = await pdfDoc.getPage(1);
  const viewport = page.getViewport({ scale: 1.5 });
  const canvas = document.createElement('canvas');
  const context = canvas.getContext('2d');
  canvas.height = viewport.height;
  canvas.width = viewport.width;
  container.appendChild(canvas);
  await page.render({ canvasContext: context, viewport: viewport }).promise;
}

获取修改后的数据并生成扁平化PDF

async function exportFlattenedPDF(originalTemplateBytes) {
  // 1. 通过PDF.js获取所有表单字段的当前值
  const fields = await window.currentPdfForm.getFields();
  const modifiedData = {};
  for (const field of fields) {
    const fieldName = field.getName();
    modifiedData[fieldName] = await field.getValue();
  }

  // 2. 用pdf-lib重新加载原始模板,填充修改后的数据并扁平化
  const finalPdfDoc = await PDFLib.PDFDocument.load(originalTemplateBytes);
  const finalForm = finalPdfDoc.getForm();
  Object.keys(modifiedData).forEach(fieldName => {
    const field = finalForm.getField(fieldName);
    if (field) field.setText(modifiedData[fieldName]);
  });
  // 扁平化表单(转为静态内容,不可编辑)
  finalForm.flatten();

  // 3. 下载生成的PDF
  const finalBytes = await finalPdfDoc.save();
  const blob = new Blob([finalBytes], { type: 'application/pdf' });
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = 'final-flattened.pdf';
  link.click();
  URL.revokeObjectURL(url);
}

关键注意事项

  • PDF.js的worker文件必须和主文件同域,否则会出现跨域错误,建议本地部署而非CDN
  • 如果需要完整的PDF查看功能(分页、缩放、工具栏),可以直接使用PDF.js官方的viewer.html组件,集成更简单
  • 扁平化操作必须基于原始模板重新生成,直接导出PDF.js的修改后文档可能仍保留可编辑字段,用pdf-lib的flatten()方法能确保表单转为静态文本

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 17:33:11