Skip to content

Instantly share code, notes, and snippets.

@webshared
Last active September 30, 2022 09:32
Show Gist options
  • Save webshared/dd2e257f669b1a5ca06e4f4514326d3b to your computer and use it in GitHub Desktop.
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
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;
@gauravksingh
Copy link

Any idea how can we do the same with react-pdf/renderer instead of react-pdf/core?

@Oosasukel
Copy link

Oosasukel commented Oct 8, 2020

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>

@rpilev
Copy link

rpilev commented Mar 30, 2021

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?

@Oosasukel
Copy link

@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:

image

image

2. I transformed the url into a canvas passing the desired page, if you have many pages:

image

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

image

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment