0

Does pdf.js allow to render a PDF page only partially? More specifically, is it possible to tell pdf.js to render a selected "rectangle of pixels" out of an entire PDF page?

Assuming a resolution of 144 dpi, a typical page (DIN A4) would have approx. 684 (width) by 1190 (height) pixels. I would like to render (for example) a rectangle like [100, 100] (top left coordinate in pixels) and [400, 400] (bottom right coordinate in pixels).

A typical use case could be a scanned document with several handwritten notes that I would like to display and further process individually.

I do understand that a "workaround" could be to save the entire page as jpg (or any other suitable bitmap format) and apply some clipping function. But this would for sure be a less performant approach than selected rendering.

pdfs.js uses a viewport object (presumably containing parameters) for rendering. This object contains

  • height
  • width
  • offsetX
  • offsetY
  • rotation
  • scale
  • transform
  • viewBox (by default [0, 0, width / scale, height / scale])

One might think that manipulating the viewBox inside it might lead to the desired outcome, but I have found that changing the viewBox parameters does not do anything at all. The entire page is rendered every time that I apply the render method.

What might I have done wrong? Does pdf.js offer the desired functionality? And if so, how can I get it to work? Thank you very much!

Here is a very simple React component demonstrating my approach (that does not work):

import React, { useRef } from 'react';
import { pdfjs } from 'react-pdf';

pdfjs.GlobalWorkerOptions.workerSrc = 'pdf.worker.js';

function PdfTest() {
  // useRef hooks
  const myCanvas: React.RefObject<HTMLCanvasElement> = useRef(null);

  const test = () => {
    const loadDocument = pdfjs.getDocument('...');
    loadDocument.promise
      .then((pdf) => {
        return pdf.getPage(1);
      })
      .then((page) => {
        const viewport = page.getViewport({ scale: 2 });

        // Here I modify the viewport object on purpose
        viewport.viewBox = [100, 100, 400, 400];

        if (myCanvas.current) {
          const context = myCanvas.current.getContext('2d');
          if (context) {
            page.render({ canvasContext: context, viewport: viewport });
            myCanvas.current.height = viewport.height;
            myCanvas.current.width = viewport.width;
          }
        }
      });
  };

  // Render function
  return (
    <div>
      <button onClick={test}>Test!</button>
      <canvas ref={myCanvas} />
    </div>
  );
}

export default PdfTest;

1 Answer 1

0

My initial thought was also to modify a viewBox of page Viewport. This was not the right guess (I hope that you already figured it out).

What do you need really to do to project only a part of a page to canvas is to prepare correctly the transformation of Viewport. So it will look more or less like following:

    const scale = 2
    const viewport = page.getViewport({ 
      scale, 
      offsetX: -100 * scale, 
      offsetY: - 100 * scale 
    })

This will move your your box section to the beginning of the canvas coordinates.

What probably you would like to do next is to make a canvas equal to the selected rectangle size (in your case is 300x300 scaled by your scale) and this solved the issue in my case.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.