Search code examples
javascripthtmlgwtpdf.js

Links, Hyperlinks into a canvas using PDF.js


I'm using the PDF.js library to render a pdf into the canvas. That pdf has hyperlinks in there, The PDF.js library is drawing the pdf into the canvas but the hyperlinks don't work.

Any Idea if it possible that hyperlinks work into the canvas?

Thanks


Solution

  • Here is a working fiddle that shows you how to enable annotations (including hyperlinks) in PDF files. The original PDF file used in the fiddle is here.

    I used viewer code at that time [note these are OLD links, now redundant] https://github.com/mozilla/pdf.js/blob/master/web/page_view.js and https://github.com/mozilla/pdf.js/blob/master/web/viewer.css as reference to write this fiddle.

    This will work but is using older libraries.
    HTML:

    <!doctype html>
    <html lang="en">
      <head>
        <link href="style.css" rel="stylesheet" media="screen" />
        <script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
        <script src="https://seikichi.github.io/tmp/PDFJS.0.8.715/pdf.min.js" type="text/javascript"></script>
        <script src="https://seikichi.github.io/tmp/PDFJS.0.8.715/ui_utils.js"></script>
        <script src="./main.js" type="text/javascript"></script>
      </head>
      <body>
        <div id="pdfContainer" class="pdf-content">
          <canvas id="the-canvas"></canvas>
          <div class="annotationLayer"></div>
        </div>
      </body>
    </html>
    

    CSS:

    body {
        font-family: arial, verdana, sans-serif;
    }
    .pdf-content {
        border: 1px solid #000000;
    }
    .annotationLayer > a {
        display: block;
        position: absolute;
    }
    .annotationLayer > a:hover {
        opacity: 0.2;
        background: #ff0;
        box-shadow: 0px 2px 10px #ff0;
    }
    .annotText > div {
        z-index: 200;
        position: absolute;
        padding: 0.6em;
        max-width: 20em;
        background-color: #FFFF99;
        box-shadow: 0px 2px 10px #333;
        border-radius: 7px;
    }
    .annotText > img {
        position: absolute;
        opacity: 0.6;
    }
    .annotText > img:hover {
        opacity: 1;
    }
    .annotText > div > h1 {
        font-size: 1.2em;
        border-bottom: 1px solid #000000;
        margin: 0px;
    }
    

    JavaScript:

    PDFJS.workerSrc = 'https://seikichi.github.io/tmp/PDFJS.0.8.715/pdf.min.worker.js';
    
    $(function () {
      var pdfData = loadPDFData();
    
      PDFJS.getDocument(pdfData).then(function (pdf) {
        return pdf.getPage(1);
      }).then(function (page) {
        var scale = 1;
        var viewport = page.getViewport(scale);
        var $canvas = $('#the-canvas');
        var canvas = $canvas.get(0);
        var context = canvas.getContext("2d");
        canvas.height = viewport.height;
        canvas.width = viewport.width;
    
        var $pdfContainer = $("#pdfContainer");
        $pdfContainer.css("height", canvas.height + "px")
          .css("width", canvas.width + "px");
    
        var renderContext = {
          canvasContext: context,
          viewport: viewport
        };
        page.render(renderContext);
        setupAnnotations(page, viewport, canvas, $('.annotationLayer'));
      });
    
      function setupAnnotations(page, viewport, canvas, $annotationLayerDiv) {
        var canvasOffset = $(canvas).offset();
        var promise = page.getAnnotations().then(function (annotationsData) {
          viewport = viewport.clone({
            dontFlip: true
          });
    
          for (var i = 0; i < annotationsData.length; i++) {
            var data = annotationsData[i];
            var annotation = PDFJS.Annotation.fromData(data);
            if (!annotation || !annotation.hasHtml()) {
              continue;
            }
    
            var element = annotation.getHtmlElement(page.commonObjs);
            data = annotation.getData();
            var rect = data.rect;
            var view = page.view;
            rect = PDFJS.Util.normalizeRect([
              rect[0],
              view[3] - rect[1] + view[1],
              rect[2],
              view[3] - rect[3] + view[1]]);
            element.style.left = (canvasOffset.left + rect[0]) + 'px';
            element.style.top = (canvasOffset.top + rect[1]) + 'px';
            element.style.position = 'absolute';
    
            var transform = viewport.transform;
            var transformStr = 'matrix(' + transform.join(',') + ')';
            CustomStyle.setProp('transform', element, transformStr);
            var transformOriginStr = -rect[0] + 'px ' + -rect[1] + 'px';
            CustomStyle.setProp('transformOrigin', element, transformOriginStr);
    
            if (data.subtype === 'Link' && !data.url) {
              // In this example,  I do not handle the `Link` annotations without url.
              // If you want to handle those annotations, see `web/page_view.js`.
              continue;
            }
            $annotationLayerDiv.append(element);
          }
        });
        return promise;
      }
    });
    
    function loadPDFData() {
      /*jshint multistr: true */
      var base64pdfData = '...'; //should contain base64 representing the PDF
    
      function base64ToUint8Array(base64) {
        var raw = atob(base64);
        var uint8Array = new Uint8Array(new ArrayBuffer(raw.length));
        for (var i = 0, len = raw.length; i < len; ++i) {
          uint8Array[i] = raw.charCodeAt(i);
        }
        return uint8Array;
      }
      return base64ToUint8Array(base64pdfData);
    }