Last active
September 30, 2022 09:32
-
-
Save webshared/dd2e257f669b1a5ca06e4f4514326d3b to your computer and use it in GitHub Desktop.
React-Pdf workaround: renders PDF as Blob in browser and display at page + show download link
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { | |
Page, Text, Image, View, Document, StyleSheet, | |
createElement, pdf, PDFRenderer, | |
} from '@react-pdf/core'; | |
import blobStream from 'blob-stream'; | |
const Doc = () => ( | |
<Document> | |
<Page wrap={true}> | |
<Text fixed={true}> | |
~ HELLO PDF RENDERER ~ | |
</Text> | |
</Page> | |
</Document> | |
); | |
class Pdf extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
downloadUrl: null, | |
} | |
this.pdfNode = null; | |
this.setPdfRef = elem => { | |
this.pdfNode = elem; | |
}; | |
this.renderPdf = async () => { | |
if (this.pdfNode) { | |
// Render the PDF here | |
const element = <Doc />; | |
const container = createElement('ROOT'); | |
const node = PDFRenderer.createContainer(container); | |
PDFRenderer.updateContainer(element, node, null); | |
const buffer = await pdf(container).toBuffer(); | |
const stream = buffer.pipe(blobStream()); | |
const url = await new Promise((resolve, reject) => { | |
stream.on('finish', () => { | |
resolve(stream.toBlobURL('application/pdf')); | |
}); | |
stream.on('error', reject); | |
}); | |
this.setState({downloadUrl: url}); | |
this.pdfNode.src = url; | |
} | |
} | |
} | |
componentDidMount() { | |
this.renderPdf(); | |
} | |
render() { | |
return ( | |
<div> | |
{this.state.downloadUrl && ( | |
<div><a href={this.state.downloadUrl} download="file.pdf">Download PDF</a></div> | |
)} | |
<iframe style={{width: 700, height: 800}} ref={this.setPdfRef}> | |
</iframe> | |
</div> | |
); | |
} | |
} | |
export default Pdf; |
With react-pdf/renderer
To display download link:
import { PDFDownloadLink } from '@react-pdf/renderer';
...
<PDFDownloadLink document={<Doc />} fileName="somename.pdf">
{({ blob, url, loading, error }) => (loading ? 'Loading document...' : 'Download now!')}
</PDFDownloadLink>
To render in DOM:
import { PDFDownloadLink } from '@react-pdf/renderer';
...
<PDFViewer>
<Doc />
</PDFViewer>
Is there any way to hide the browser built in menu that appears along with the PDF? What about rendering a specific page and not the whole document?
Another issue is that scrolling does not seem to bubble out to the parent if the mouse is over the document itself, but it does when the mouse is over the built in PDF menu. So basically if I scroll to the end of a document the parent doesn't start scrolling if I keep scrolling. Any workaround possible?
@rpilev, I got it using the lib pdfjs-dist
You should be able to improve this logic, but it is a way that I was able to do haha 😅
1. I transformed the document into a url:
2. I transformed the url into a canvas passing the desired page, if you have many pages:
import workerURL from './pdf.worker.min.es5.data';
var pdfjsLib = require('pdfjs-dist/es5/build/pdf');
interface pdfToCanvasResponse {
canvas: HTMLCanvasElement | null;
pages: number;
}
/** This function returns a canvas or undefined if pdfUrl is not valid */
function pdfToCanvas(
pdfUrl: string | null | undefined,
pageToDisplay: number
): Promise<pdfToCanvasResponse> {
return new Promise((resolve) => {
if (pdfUrl) {
pdfjsLib.GlobalWorkerOptions.workerSrc = workerURL;
const loadingTask = pdfjsLib.getDocument(pdfUrl);
loadingTask.promise.then(function (pdf: any) {
const pages = pdf.numPages;
if (pageToDisplay > pages) {
pageToDisplay = pages;
}
pdf.getPage(pageToDisplay).then(function (page: any) {
const viewport = page.getViewport({ scale: 2 });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
if (context) {
const renderContext = {
canvasContext: context,
viewport: viewport,
};
page.render(renderContext).promise.then(() => {
resolve({ canvas, pages });
});
} else {
resolve({ canvas: null, pages: 0 });
}
});
});
} else {
resolve({ canvas: null, pages: 0 });
}
});
}
export default pdfToCanvas;
3. I drew this canvas on another canvas that was in html
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Any idea how can we do the same with react-pdf/renderer instead of react-pdf/core?