PDF.js cannot display rendered canvas image
P粉766520991
2023-08-17 20:02:20
<p>I have a React component that displays a PDF. When I use this component, I just need to pass the URL of the PDF. </p>
<pre class="brush:php;toolbar:false;"><Previewer pdfUrl={pdfUrl}></Previewer></pre>
<p>The component handles the details of the preview. The problem I'm having is that this component doesn't display the PDF.Am I missing something? What should I do to solve this problem?下面是一个演示:</p>
<p><br /></p>
<pre class="snippet-code-js lang-js prettyprint-override"><code>const { StrictMode, useRef } = React;
const { createRoot } = ReactDOM;
const styles = {};
const Previewer = (props) => {
const canvasRef = useRef(null);
React.useEffect(() => {
if (props.pdfUrl) {
initPdf(props.pdfUrl);
}
}, []);
// Converted async/await function to use promise because Stack Snippet's Babel version does not support async/await
const initPdf = (pdfUrl) => {
// Reference CDN version of PDF.js instead of using ES6 import
const pdfJS = pdfjsLib;
pdfJS.GlobalWorkerOptions.workerSrc = "https://unpkg.com/pdfjs-dist@3.9.179/build/pdf.worker.js";
return pdfJS.getDocument({
url: pdfUrl,
cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.9.179/cmaps/',
cMapPacked: true,
}).promise.then((pdf) => {
const totalPages = pdf.numPages;
for (let i = 0; i < totalPages; i ) {
renderPdfPage(pdf, pdfJS, i 1);
}
});
}
// Converted async/await function to use promise because Stack Snippet's Babel version does not support async/await
const renderPdfPage = (pdf, pdfJS, pageNum) => {
return pdf.getPage(pageNum).then((page) => {
const viewport = page.getViewport({
scale: 1.0
});
let divPage = window.document.createElement("div");
if(!canvasRef || !canvasRef.current) return;
let canvas = divPage.appendChild(window.document.createElement("canvas"));
const canvasContext = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
const renderContext = { canvasContext, viewport };
const renderTask = page.render(renderContext);
renderTask.promise.then(function () {
const textContent = page.getTextContent();
return textContent;
}).then(function (textContent) {
const textLayer = document.querySelector(`.${styles.textLayer}`);
if (!textLayer) return;
textLayer.style.left = canvas.offsetLeft 'px';
textLayer.style.top = canvas.offsetTop 'px';
textLayer.style.height = canvas.offsetHeight 'px';
textLayer.style.width = canvas.offsetWidth 'px';
textLayer.style.setProperty('--scale-factor', '1.0');
pdfJS.renderTextLayer({
textContentSource: textContent,
container: textLayer,
viewport: viewport,
textDivs: []
});
});
canvasRef.current.appendChild(divPage);
});
}
return (
<div className={styles.cavasLayer}>
<canvas id="the-cavas" ref={canvasRef} />
{/**<div className={styles.textLayer}></div>**/}
</div>
);
}
const pdfUrl = "https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf"
const root = createRoot(document.getElementById("root"));
root.render(<StrictMode><Previewer pdfUrl={pdfUrl} /></StrictMode>);</code></pre>
<pre class="snippet-code-html lang-html prettyprint-override"><code><script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/pdfjs-dist@3.9.179/build/pdf.js"></script>
<div id="root"></div></code></pre>
<p><br /></p>
question
In the
renderPdfPage
function, you create adiv
element that contains thecanvas
element that renders the PDF page. Then append thesediv
elements to acanvas
element. However, if the browser supports thecanvas
element, descendant elements of thecanvas
element will not be rendered. According to the specification of the canvas element:The rollback content is defined as follows:
solution
You need to change the parent
canvas
to the appropriate element. In the demo below, I'm using adiv
: