在 React 中使用 OffScreenCanvas 将 HTML 转换为 PDF
Convert HTML to PDF Using OffScreenCanvas in React
好的,所以这个问题是不言自明的。
目前,我正在做以下事情
- 使用 html2canvas npm 包将我的 html 转换为 canvas.
- 正在将 Canvas 转换为图像
canvas.toDataURL("image/png");
- 使用 jsPDF 在一些操作后使用此图像创建 pdf。
所以基本上所有这个过程都是 CPU 密集的并且会导致页面无响应。
我正在尝试将流程卸载给网络工作者,但我无法将 HTML 节点或 Canvas 元素发送到我的工作线程。
因此,尝试使用 OffScreenCanvas,但我不知道如何继续使用它。
第一步无法在Web-Worker中完成。您需要访问 DOM 才能绘制它,而工人无权访问 DOM.
第二步 可以在 OffscreenCanvas 上完成,html2canvas 接受 { canvas }
参数,您还可以将其设置为 OffscreenCanvas.
但是一旦你从 OffscreenCanvas 获得上下文,你就不能再传输它,所以你将无法将 OffscreenCanvas 传递给Worker 和你不会从中获得任何好处,因为一切仍将在 UI 线程上完成。
所以我们能做的最好的事情就是让 html2canvas 初始化一个 HTMLCanvasElement,在上面绘制,然后将其转换为 Blob 中的图像。 Blob 可以在没有任何复制成本的情况下遍历领域,并且 toBlob()
方法可以异步完成其压缩部分。
第三步可以在Worker中完成,因为this PR。
我不知道反应所以你将不得不重写它,但这是一个简单的 JS 实现:
script.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,这里是 outsourced live example.
好的,所以这个问题是不言自明的。
目前,我正在做以下事情
- 使用 html2canvas npm 包将我的 html 转换为 canvas.
- 正在将 Canvas 转换为图像
canvas.toDataURL("image/png");
- 使用 jsPDF 在一些操作后使用此图像创建 pdf。
所以基本上所有这个过程都是 CPU 密集的并且会导致页面无响应。
我正在尝试将流程卸载给网络工作者,但我无法将 HTML 节点或 Canvas 元素发送到我的工作线程。
因此,尝试使用 OffScreenCanvas,但我不知道如何继续使用它。
第一步无法在Web-Worker中完成。您需要访问 DOM 才能绘制它,而工人无权访问 DOM.
第二步 可以在 OffscreenCanvas 上完成,html2canvas 接受 { canvas }
参数,您还可以将其设置为 OffscreenCanvas.
但是一旦你从 OffscreenCanvas 获得上下文,你就不能再传输它,所以你将无法将 OffscreenCanvas 传递给Worker 和你不会从中获得任何好处,因为一切仍将在 UI 线程上完成。
所以我们能做的最好的事情就是让 html2canvas 初始化一个 HTMLCanvasElement,在上面绘制,然后将其转换为 Blob 中的图像。 Blob 可以在没有任何复制成本的情况下遍历领域,并且 toBlob()
方法可以异步完成其压缩部分。
第三步可以在Worker中完成,因为this PR。
我不知道反应所以你将不得不重写它,但这是一个简单的 JS 实现:
script.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,这里是 outsourced live example.