首页 > 解决方案 > 在 React 中使用 OffScreenCanvas 将 HTML 转换为 PDF

问题描述

好的,所以这个问题是不言自明的。

目前,我正在执行以下操作

  1. 使用 html2canvas npm 包将我的 html 转换为画布。
  2. 将画布转换为图像
         canvas.toDataURL("image/png");
  1. 经过一些操作后,使用 jsPDF 使用此图像创建 pdf。

所以基本上所有这些过程都是 CPU 密集型的,并导致页面无响应。

我正在尝试将进程卸载到网络工作者,但我无法将 HTML 节点或画布元素 postMessage 到我的工作者线程。

因此,尝试使用 OffScreenCanvas 但我对如何继续这样做感到困惑。

标签: jspdfweb-workerhtml2canvasoffscreen-canvas

解决方案


第一步不能在 Web-Worker 中完成。您需要访问 DOM 才能绘制它,而 Workers 无权访问 DOM。

第二步可以在OffscreenCanvas上完成,html2canvas确实接受一个{ canvas }您也可以设置为OffscreenCanvas的参数。但是,一旦您从OffscreenCanvas
获得上下文,您就无法再传输它,因此您将无法将该OffscreenCanvas传递给 Worker,并且您不会从中获得任何收益,因为一切仍将在 UI 线程上完成. 所以我们能做的最好的就是让html2canvas初始化一个HTMLCanvasElement,在它上面绘图,然后将它转换成一个 Blob 中的图像。Blob 可以在没有任何复制成本的情况下穿越领域,并且
toBlob()方法可以使其压缩部分异步完成。

第三步可以在 Worker 中完成,因为这个 PR

我不知道反应所以你将不得不重写它,但这里是一个裸 JS 实现:

脚本.js

const dpr = window.devicePixelRatio;
const worker = new Worker( "worker.js" );
worker.onmessage = makeDownloadLink;
worker.onerror = console.error;

html2canvas( target ).then( canvas => {
  canvas.toBlob( (blob) => worker.postMessage( {
    source: blob,
    width: canvas.width / dpr, // retina?
    height: canvas.height / dpr // retina?
  } ) );
} );

worker.js

importScripts( "https://unpkg.com/jspdf@latest/dist/jspdf.umd.min.js" );
onmessage = ({ data }) => {
  const { source, width, height } = data;
  const reader = new FileReaderSync();
  const data_url = reader.readAsDataURL( source );
  const doc = new jspdf.jsPDF( { unit: "px", format: [ width, height ], orientation: width > height ? "l" : "p" });
  doc.addImage( data_url, "PNG", 0, 0, width, height, { compression: "NONE" } );
  postMessage( doc.output( "blob" ) );
};

而且由于 StackSnippet 的过度保护 iframe 确实会破坏html2canvas,因此这里有一个外包的实时示例


推荐阅读