Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PDF.JS How to make pdf-js viewer canvas responsive?

I have to display PDF using PDFJS library on my page. The problem is that since I give the scale as a fixed number canvas in which PDF is rendered is not responsive and does not fit the bootstrap grid column width. Here is HTML code:

<div class="row">
   <div class="col-md-1" style="padding-right: 15px;">
     <input type="button" ng-click="openPreviousPage()"/>
   </div>
   <div class="col-md-8">
     <canvas id="the-canvas" style="border: 1px solid black;"></canvas>
    </div>
    <div class="col-md-1 col-md-offset-2" style="padding-right:15px;">
      <input type="button" ng-click="openNextPage()" />
    </div>
</div>

and my Typescript in a controller:

 openPage = (pdf: PDFDocumentProxy, pageNumber: number) => {
        pdf.getPage(pageNumber).then(function getPage(page) {
            var scale = 1;
            var viewport = page.getViewport(scale);

            var canvas = <HTMLCanvasElement>document.getElementById('the-canvas');
            var context = canvas.getContext('2d');
            canvas.height = viewport.height;
            canvas.width = viewport.width;


            var renderContext = {
                canvasContext: context,
                viewport: viewport
            };

            //...rest of actions
        });
    }

Would be grateful for any hint.

like image 655
cAMPy Avatar asked Mar 14 '16 12:03

cAMPy


3 Answers

You can put an id on the canvas container div and set the scale based upon div.clientWidth and viewport.width.

On your HTML code:

<div class="row">
  <div class="col-md-1" style="padding-right: 15px;">
    <input type="button" ng-click="openPreviousPage()"/>
  </div>
  <div class="col-md-8" id="the-container">
    <canvas id="the-canvas" style="border: 1px solid black;"></canvas>
  </div>
  <div class="col-md-1 col-md-offset-2" style="padding-right:15px;">
    <input type="button" ng-click="openNextPage()" />
  </div>
</div>

Then on the controller:

openPage = (pdf: PDFDocumentProxy, pageNumber: number) => {
    pdf.getPage(pageNumber).then(function getPage(page) {
        var container = document.getElementById('the-container');
        var canvas = <HTMLCanvasElement>document.getElementById('the-canvas');
        var context = canvas.getContext('2d');

        var viewport = page.getViewport(1);
        var scale = container.clientWidth / viewport.width;
        viewport = page.getViewport(scale);

        canvas.height = viewport.height;
        canvas.width = viewport.width;


        var renderContext = {
            canvasContext: context,
            viewport: viewport
        };

        //...rest of actions
    });
}

Hope this helps...

like image 92
Tony G. Bolaño Avatar answered Nov 16 '22 00:11

Tony G. Bolaño


For anybody working from the Acroforms example as their starting point, you may notice that viewport.width does not match what is being rendered on the screen when you inspect, which makes the above solution render the PDF larger than desired. In my case, viewport.width was 612, but was rendering to 816. I finally figured out that this is a result of the CSS_UNITS variable that lives inside pdf_viewer.js. Once I figured that out, I honed my Google search and found the conversation discussing its purpose:

"In the html/css world 1in = 96pixels, in PDF the default is 1in = 72pixels. The scale is used so when showing 100% a PDF that is 8.5in should show up on the screen as 8.5in."

To adjust for this variable, which isn't global, I just declared it again locally and then adjusted the scale formula above to include it, like this:

    'use strict';

    PDFJS.workerSrc = '/assets/plugins/PDFjs/web/test/pdf.worker.js';

    var DEFAULT_URL = '/assets/plugins/PDFjs/web/test/form.pdf';
    var DEFAULT_SCALE = 1.0;
    var CSS_UNITS = 96/72;
    var container = document.getElementById('pageContainer');

    // Fetch the PDF document from the URL using promises.
    PDFJS.getDocument(DEFAULT_URL).then(function (doc) {

      // Use a promise to fetch and render the next page.
      var promise = Promise.resolve();
      for (var i = 1; i <= doc.numPages; i++) {
          promise = promise.then(function (pageNum) {
            return doc.getPage(pageNum).then(function (pdfPage) {

                var viewport = pdfPage.getViewport(DEFAULT_SCALE);
                var scale = container.clientWidth / (viewport.width * CSS_UNITS);

                // Create the page view.
                var pdfPageView = new PDFJS.PDFPageView({
                  container: container,
                  id: pageNum,
                  scale: scale,
                  defaultViewport: pdfPage.getViewport(scale),
                  annotationLayerFactory: new PDFJS.DefaultAnnotationLayerFactory(),
                  renderInteractiveForms: true,
                });

            // Associate the actual page with the view and draw it.
            pdfPageView.setPdfPage(pdfPage);
            return pdfPageView.draw();
          });
        }.bind(null, i));
      }
    });

It works well for me now. Hope I was able to save one of you some time. :)

Cheers!

like image 37
Joshua Hutchison Avatar answered Nov 16 '22 00:11

Joshua Hutchison


Use bootstrap and put class = "img-fluid" in your canvas.

 <div class="container" id="the-container">
    <canvas id="the-canvas" class="img-fluid" style="border: 1px solid black;"></canvas>
  </div>
like image 2
KameiBR Avatar answered Nov 15 '22 23:11

KameiBR