PDFjs-based Viewer Embedded In Any Web Page

PDFjs Viewer is customizable and has different options and callbacks that enable it to be easily integrated into your application. PDF js Viewer is an embeddable and easily customizable PDF viewer implemented using the PDF.js library.

Some of them are included in the distribution:

  • A simple PDF viewer for a simple document.
  • PDF viewer with a toolbar that enables you to navigate through the document.
  • PDF viewer with thumbnails that interact with the main document.
  • A PDF viewer with which selections can be created and moved across different pages.

Note: PDFjs-viewer was written from scratch and has nothing to do with the viewer example in the PDF.js distribution.

Technical Facts

  • The pages of each document are rendered on demand, to avoid browser memory usage. The viewer detects which pages are visible and displays each one. Although rendering is fast, with options (such as extraPagesToLoad) It is recommended to display a few more pages to enable a better user experience when scrolling through the document.
  • PDFjs viewer adds some callbacks that are called on different events: onDocumentReady, onNewPage, onPageRender, onZoomChange, onActivePageChanged. Each callback is bound to the PDFjsViewer instance, so it’s possible to use this to refer to it.
  • PDFjs-viewer renders pages according to the size of the DIV elements they are embedded in. In this way, the memory size is set to the minimum required. It is important that PDFjsViewer considers the pixel_ratio feature to increase the resolution of images according to the features of the device on which the document is opened (eg retina screens, etc.).
  • PDFjs Viewer includes support for zooming pages, so the user does not need to deal with this typical feature.

Must Read: An Angular Component for PDFJS and ViewerJS | ng2-pdfjs-viewer

How to make use of it:

1. Load the necessary jQuery and pdf.js libraries into the document.

<script src="/path/to/cdn/jquery.min.js"></script>
<script src="/path/to/cdn/pdf.min.js"></script>

2. Load the material icons.

<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Outlined" rel="stylesheet">

3. Load the pdfjs-viewer plugin files.

<!-- Core -->
<script src="/js/pdfjs-viewer.js"></script>
<link rel="stylesheet" href="/css/pdfjs-viewer.css">
<!-- Optional Toolbar Stylesheet -->
<link rel="stylesheet" href="/css/pdftoolbar.css">

4. Configure the pdf.js library.

// Let's initialize the PDFjs library
var pdfjsLib = window['pdfjs-dist/build/pdf'];

// The workerSrc property shall be specified.
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.worker.min.js';

5. Embed the PDF viewer into the HTML element you select.

<div class="pdfpages">
  <div class="pdfpage placeholder">
    <p>No file loaded</p>
  </div>
</div>
// override the PDF path
let PDFFILE="test.pdf";

let pdfViewer = new PDFjsViewer($('.pdfpages'));
pdfViewer.loadDocument(PDFFILE).then(function() {
  pdfViewer.setZoom("fit");
});

6. Add a custom toolbar to the PDF viewer.

<div class="pdftoolbar">
  <button class="btn-first" onclick="pdfViewer.first()"><i class="material-icons-outlined">skip_previous</i></button>
  <button class="btn-prev" onclick="pdfViewer.prev(); return false;"><i class="material-icons-outlined">navigate_before</i></button>
  <span class="pageno"></span>
  <button class="btn-next" onclick="pdfViewer.next(); return false;"><i class="material-icons-outlined">navigate_next</i></button>
  <button class="btn-last" onclick="pdfViewer.last()"><i class="material-icons-outlined">skip_next</i></button>

  <button onclick="pdfViewer.setZoom('out')"><i class="material-icons-outlined">zoom_out</i></button>
  <span class="zoomval">100%</span>
  <button onclick="pdfViewer.setZoom('in')"><i class="material-icons-outlined">zoom_in</i></button>
  <button class="ms-3" onclick="pdfViewer.setZoom('width')"><i class="material-icons-outlined">swap_horiz</i></button>
  <button onclick="pdfViewer.setZoom('height')"><i class="material-icons-outlined">swap_vert</i></button>
  <button onclick="pdfViewer.setZoom('fit')"><i class="material-icons-outlined">fit_screen</i></button>
</div>
let pdfViewer = new PDFjsViewer($('.pdfjs-viewer'), {
    onZoomChange: function(zoom) {
        zoom = parseInt(zoom * 10000) / 100;
        $('.zoomval').text(zoom + '%');
    },
    onActivePageChanged: function(page, pageno) {
        $('.pageno').text(pageno + '/' + this.getPageCount());
    },
});
pdfViewer.loadDocument("test.pdf").then(function() {
    pdfViewer.setZoom('fit');
});

7. This example shows how to create a full-screen PDF viewer with thumbnail support.

<!-- Toolbar -->
<div class="pdftoolbar">
  <button class="" onclick="pdfViewer.prev();"><i class="material-icons-outlined">arrow_upward</i></button>
  <div class="v-sep"></div>
  <button class="" onclick="pdfViewer.next();"><i class="material-icons-outlined">arrow_downward</i></button>
  <input id="pageno" class="pageno" type="number" class="form-control form-control-sm d-inline w-auto" value="1" min="1" max="1000" onchange="pdfViewer.scrollToPage(parseInt(this.value))">
  <span id="pagecount" class="pageno"></span>
  <div class="divider"></div>
  <button onclick="setZoom('in')"><i class="material-icons-outlined">add</i></button>
  <div class="v-sep"></div>
  <button onclick="setZoom('out')"><i class="material-icons-outlined">remove</i></button>
  <div class="dropdown">
    <div class="dropdown-value" onclick="this.parentNode.classList.toggle('show');">
      <span class="zoomval">100%</span>
      <i class="material-icons-outlined">
        keyboard_arrow_down
      </i>                    
    </div>
    <div class="dropdown-content" onclick="this.parentNode.classList.toggle('show');">
      <a href="#" data-zoom="width" onclick='setZoom(this); return false;'>Adjust width</a>
      <a href="#" data-zoom="height" onclick='setZoom(this); return false;'>Adjust height</a>
      <a href="#" data-zoom="fit" onclick='setZoom(this); return false;'>Fit page</a>
      <a href="#" data-zoom="0.5" onclick='setZoom(this); return false;'>50%</a>
      <a href="#" data-zoom="0.75" onclick='setZoom(this); return false;'>75%</a>
      <a href="#" data-zoom="1" onclick='setZoom(this); return false;'>100%</a>
      <a href="#" data-zoom="1.25" onclick='setZoom(this); return false;'>125%</a>
      <a href="#" data-zoom="1.5" onclick='setZoom(this); return false;'>150%</a>
      <a href="#" data-zoom="2" onclick='setZoom(this); return false;'>200%</a>
      <a href="#" data-zoom="3" onclick='setZoom(this); return false;'>300%</a>
      <a href="#" data-zoom="4" onclick='setZoom(this); return false;'>400%</a>
    </div>                    
  </div>
  <div class="divider"></div>
  <button class="btn-first" onclick="window.open(PDFFILE, '_blank')"><i class="material-icons-outlined">file_download</i></button>
  <div class="dropdown dropdown-right">
    <div onclick="this.parentNode.classList.toggle('show');">
      <button><i class="material-icons-outlined">keyboard_double_arrow_right</i></button>
    </div>
    <div class="dropdown-content" onclick="this.parentNode.classList.toggle('show');">
      <a href="#" onclick='pdfViewer.scrollToPage(1); return false;'><i class="material-icons-outlined">vertical_align_top</i>First page</a>
      <a href="#" onclick='pdfViewer.scrollToPage(pdfViewer.pdf.numPages); return false;'><i class="material-icons-outlined">vertical_align_bottom</i>Last page</a>
      <div class="h-sep"></div>
      <a href="#" onclick='document.querySelector(".pdfpages").classList.remove("horizontal-scroll"); pdfViewer.refreshAll();'><i class="material-icons-outlined">more_vert</i>Vertical scroll</a>
      <a href="#" onclick='setHorizontal()'><i class="material-icons-outlined">more_horiz</i>Horizontal scroll</a>
    </div>                    
  </div>                
</div>
<!-- Thumbnail -->
<div class="thumbnails">
</div>
<div class="hider">
  <a class="my-auto fold" href="#" onclick="hidethumbs(); return false;">
    <i class="material-icons-outlined">keyboard_double_arrow_left</i>
  </a>
  <a class="my-auto unfold" href="#" onclick="showthumbs(); return false;">
    <i class="material-icons-outlined">keyboard_double_arrow_right</i>
  </a>
</div>

<!-- PDF viewer -->
<div class="pdfpages">
  <div class="pdfpage placeholder">
    <p>No file loaded</p>
  </div>
</div>  
let PDFFILE="test.pdf";
function dataURItoBinArray(data) {
    // taken from: https://stackoverflow.com/a/11954337/14699733
    var binary = atob(data);
    var array = [];
    for(var i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Uint8Array(array);
}
/** Function to load a PDF file using the input=file API */
document.querySelector("#opendoc").addEventListener("change", function(e) {
    let file = e.target;
    let reader = new FileReader();
    reader.onload = async function() {
        await pdfViewer.loadDocument({data: dataURItoBinArray(reader.result.replace(/^data:.*;base64,/,""))});
        await pdfThumbnails.loadDocument({data: dataURItoBinArray(reader.result.replace(/^data:.*;base64,/,""))}).then(() => pdfThumbnails.setZoom("fit"));
    }
    if (file.files.length > 0) {
        reader.readAsDataURL(file.files[0]);
        document.querySelector('#filedownload').download = document.querySelector('#opendoc').files[0].name;
    }
});
/** Sets the document in horizontal scroll by changing the class for the pages container and refreshing the document 
 *    so that the pages may be displayed in horizontal scroll if they were not visible before */
function setHorizontal() {
    document.querySelector(".maindoc").classList.add("horizontal-scroll"); 
    pdfViewer.refreshAll();    
}
/** Toggles the visibility of the thumbnails */
function togglethumbs(el) {
    if (el.classList.contains('pushed')) {
        el.classList.remove('pushed');
        document.querySelector('.thumbnails').classList.add('hide');
    } else {
        el.classList.add('pushed');
        document.querySelector('.thumbnails').classList.remove('hide');
    }
}
/** Now create the PDFjsViewer object in the DIV */
let pdfViewer = new PDFjsViewer($('.maindoc'), {
    zoomValues: [ 0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4 ],

    /** Update the zoom value in the toolbar */
    onZoomChange: function(zoom) {
        zoom = parseInt(zoom * 10000) / 100;
        $('.zoomval').text(zoom + '%');
    },

    /** Update the active page */
    onActivePageChanged: function(page) {
        let pageno = $(page).data('page');
        let pagetotal = this.getPageCount();

        pdfThumbnails.setActivePage(pageno);
        $('#pageno').val(pageno);
        $('#pageno').attr('max', pagetotal);
        $('#pagecount').text('de ' + pagetotal);
    },

    /** zoom to fit when the document is loaded and create the object if wanted to be downloaded */
    onDocumentReady: function () {
        pdfViewer.setZoom('fit');
        pdfViewer.pdf.getData().then(function(data) {
            document.querySelector('#filedownload').href = URL.createObjectURL(new Blob([data], {type: 'application/pdf'}));
            document.querySelector('#filedownload').target = '_blank';
        });
    }
});

/** Load the initial PDF file */
pdfViewer.loadDocument(PDFFILE).then(function() {
    document.querySelector('#filedownload').download = PDFFILE;
});

/** Create the thumbnails */
let pdfThumbnails = new PDFjsViewer($('.thumbnails'), {
    zoomFillArea: 0.7,
    onNewPage: function(page) {
        page.on('click', function() {
            if (!pdfViewer.isPageVisible(page.data('page'))) {
                pdfViewer.scrollToPage(page.data('page'));
            }
        })
    },
    onDocumentReady: function() {
        this.setZoom('fit');
    }
});

pdfThumbnails.setActivePage = function(pageno) {
    this.$container.find('.pdfpage').removeClass('selected');
    let $npage = this.$container.find('.pdfpage[data-page="' + pageno + '"]').addClass('selected');
    if (!this.isPageVisible(pageno)) {
        this.scrollToPage(pageno);
    }
}.bind(pdfThumbnails);

pdfThumbnails.loadDocument(PDFFILE);

8. All options are default.

let pdfViewer = new PDFjsViewer($('.pdfpages'), {
    visibleThreshold: .5,
    extraPagesToLoad: 3,
    pageClass: "pdfpage",
    zoomValues: [ .25, .5, .75, 1, 1.25, 1.5, 2, 4, 8 ],
    zoomFillArea: .95,
    contentClass: "content-wrapper",
    // callbacks
    onDocumentReady: () => {},
    onNewPage: (page, i) => {},
    onPageRender: (page, i) => {},
    errorPage: () => {
      $(`<div class="placeholder"></div>`).addClass(this.settings.pageClass).append($(`<p class="m-auto"></p>`).text("could not load document"));
    },
    onZoomChange: zoomlevel => {},
    onActivePageChanged: (page, i) => {},
    // function to handle empty content
    emptyContent: () => $('<div class="loader"></div>')
});

9. API methods.

// load a PDF file and returns a promise
// the document can be either an url or a bin array.
pdfViewer.loadDocument(document);

// force re-init
pdfViewer.forceViewerInitialization();

// refresh all pages
pdfViewer.refreshAll();

// get the active page
pdfViewer.getActivePage();

// go to the first page
pdfViewer.first();

// go to the last page
pdfViewer.last();

// go to the next page
pdfViewer.next();

// back to the previous page
pdfViewer.prev();

// get the number of pages
pdfViewer.getPageCount();

// retrieve all the pages of the document
pdfViewer.getPages();

// go to a specific page
pdfViewer.scrollToPage(i);

// check if the page is visible
isPageVisible(i);

// set zoom level
// it is possible to use a float value which represents a fraction or a keyword 'in', 'out', 'width', 'height' or 'fit'
pdfViewer.setZoom(zoom);

// get the current zoom level
pdfViewer.getZoom();

// rotate the pages
pdfViewer.rotate(deg, accumulate = false);

Methods

The public methods of the PDFViewer class are the next:

Must Read: Wrapper for PDF JS to Add Annotations | pdfannotate.js

  • loadDocument(document): Loads the document and returns a promise to load it (so the result is then able to add actions after loading the document, or is catchable in case of error). The document can be either an URL or a bin array.
  • forceViewerInitialization(): Forces the creation (or re-creation) of the whole content of the viewer (i.e. new divs, structures, etc.). It is useful for a full refresh of the viewer (e.g. when changes the rotation of the pages).
  • refreshAll(): Recalculates which pages are now visible and forces redrawing them.
  • getActivePage(): Gets the jQuery div object corresponding to the active page (or null, if none of the pages have been set).
  • first(): Scroll to the first page of the document.
  • last(): Scroll to the last page of the document.
  • next(): Scroll to the next page (if any).
  • prev(): Scroll to the previous page (if any).
  • getPageCount(): Gets the number of pages of the document.
  • getPages(): Retrieves all the pages of the document (the page info structures).
  • scrollToPage(i): Sets the scroll position of the container to page number i
  • isPageVisible(i): Returns true if the page number i is considered to be visible
  • setZoom(zoom): Sets the current zoom level and applies it to all the pages (it is possible to use a float value which represents a fraction or a keyword ‘in’, ‘out’, ‘width’, ‘height’, or ‘fit’).
  • getZoom(): Obtain the current zoom level
  • rotate(deg, accumulate = false): Rotates the pages of the document deg degrees (if accumulate is set to false), or increases the rotation by deg degrees (it accumulate is set to true).

See Demo And Download

pdfjs-viewer-jquery

Official Website(dealfonso): Click Here

This superior jQuery/javascript plugin is developed by dealfonso. For extra advanced usage, please go to the official website.

Related Posts

Google-Translate-Dropdown-Customize-With-Country-Flag

Google Translate Dropdown Customize With Country Flag | GT API

Flag google translates jQuery text that takes advantage of the Google Cloud Translation API to translate web content between languages by selecting a country from the dropdown…

Bootstrap-Fileinput

HTML 5 File Input Optimized for Bootstrap 4.x./3.x with File Preview | Bootstrap Fileinput

bootstrap-fileinput is an improved HTML 5 file input  Bootstrap 5.x, 4.x and 3.x with file preview for different files, provides multiple selections, resumable section uploads, and more….

HStack-and-VStack-in-CSS

CSS Layout Components Horizontal/Vertical Stack | HStack and VStack

HStack and VStack in CSS – CSS layout components that (basically) stack anything horizontally and vertically. A pure CSS library that makes it easy to stack elements…

Floating-Whatsapp-Chat-Button

How to Add Floating Whatsapp Chat Button In HTML | venom-button

Venom Button is a very simple plugin for the jQuery floating WhatsApp button. Adds a floating button to your site that calls WhatsApp Click to Chat API. It will automatically start the WhatsApp…

Data-Table-Generator-Tabulator

Interactive Data Table Generator with JS/jQuery and JSON | Tabulator

Tabulator allows you to create interactive tables in seconds from any HTML Table, JavaScript array, AJAX data source, or JSON format data. Just include the library in your…

alert-confirm-prompt-attention-js

Simple Alert, Confirm, Prompt Popup Using Vanilla JavaScript Library | attention.js

JavaScript provides various built-in functionality to display popup messages for different purposes. Attention JS is a vanillaJS plugin used to create a custom alert, confirm, or Prompt…

Leave a Reply

Your email address will not be published. Required fields are marked *