pdf.js_readonly icon indicating copy to clipboard operation
pdf.js_readonly copied to clipboard

PDF.js Read Only is an additional readonly mode for PDF.js (https://mozilla.github.io/pdf.js)

PDF.js Read Only

PDF.js Read Only is an additional readonly mode for PDF.js, a Portable Document Format (PDF) viewer that is built with HTML5 which is community-driven and supported by Mozilla.

Its purpose to make PDF.js viewer to be readonly mode, including disable right click on mouse (context menu) and several hotkeys (keyboard shortcut) such as:

  • Ctrl + C (Copy Text)
  • Ctrl + O (Open PDF)
  • Ctrl + P (Print PDF)
  • Ctrl + S (Save PDF)
  • PrtSc      (Print Screen) (experimental)

Demo

A. Desktop
  1. PDF.js without read only  /generic/web/viewer.html
  2. If using PDF.js Read Only /generic/web/viewer_readonly.html
B. Mobile
  1. PDF.js without read only  /mobile-viewer/viewer.html
  2. If using PDF.js Read Only /mobile-viewer/viewer_readonly.html
C. Test
  1. PDF.js iframe read only    /test/iframe_readonly.html
  2. PDF.js mobile responsive /test/mobile_responsive.html
  3. PDF.js desktop mobile     /test/desktop_mobile.html

How To Use

A. Desktop

    Support Password Protected PDF

  1. /generic/web/viewer_readonly.html
    adjustment in viewer_readonly.html

    <!-- PDF.js Read Only Adjustment -->
    <!-- <script src="viewer.js"></script> --> <!-- you need to comment or remove this line -->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script> <!-- adjust your jquery if necessary -->
    <script src="../../js/pdf.js_readonly.js"></script> <!-- adjust path to pdf.js_readonly.js -->
    
  2. /js/pdf.js_readonly.js
    adjustment in pdf.js_readonly.js

    // Read Only Preferences
    var disableRghtClck = true; // Disable Right Click,   value: true || false
    var disableCopyText = true; // Disable Copy Text,     value: true || false
    var disableOpenFile = true; // Disable Open PDF,      value: true || false
    var disablePrintPdf = true; // Disable Print PDF,     value: true || false
    var disableDownload = true; // Disable Save PDF,      value: true || false
    var disablePresents = true; // Disable Presentation,  value: true || false
    var disablePrntScrn = true; // Disable Print Screen,  value: true || false (experimental)
    
    // Load Specific viewer.js
    if ( disablePrintPdf ) {
      $.getScript( '../../js/viewer_noprint.js' ); // Adjust path to viewer_noprint.js if necessary
    } else {
      $.getScript( 'viewer.js' );  // Adjust path to viewer.js if necessary
    }
    
  3. /js/viewer_noprint.js
    modification from viewer.js

    /*  Modified for PDF.js Read Only
     *  To disable print overlay
     */
    /* window.addEventListener("keydown", function (event) {
      if (event.keyCode === 80 && (event.ctrlKey || event.metaKey) && !event.altKey && (!event.shiftKey || window.chrome || window.opera)) {
        window.print();
        event.preventDefault();
    
        if (event.stopImmediatePropagation) {
          event.stopImmediatePropagation();
        } else {
          event.stopPropagation();
        }
      }
    }, true); */
    

    Note: If you want to create viewer_noprint.js on your own from viewer.js file of your current PDF.js version, make sure those lines above (or some codes like that) are commented.

  4. /js/viewer_noprint.js

    • to protect PDF file source
    // value: "compressed.tracemonkey-pldi-09.pdf",
    /*  Modified for PDF.js Read Only
     *  It's better to NOT having .PDF extension in the end of file name
     *  This can avoid like IDM to sniff PDF file type automatically download
     *  You also can protect PDF file source from direct access using .htaccess
     *  Or you can never reveal its original file name such as encoding it first!
     */
    value: "compressed.tracemonkey-pldi-09",
    
    • to allow access PDF file from different domain
    const HOSTED_VIEWER_ORIGINS = ["null", "http://mozilla.github.io", "https://mozilla.github.io", "https://yourdomain.here"];
    

    and makesure the PDF file webserver has HTTP Header Access-Control-Allow-Origin, allowing PDF.js viewer domain

    Access-Control-Allow-Origin: http(s)://yourPDFjsViewerDomain.here
    
  5. /generic/web/viewer_readonly.html
    adjustment in viewer_readonly.html for custom progress document loading

    <!-- PDF.js Read Only Adjustment --> 
    <!-- Custom Progress Document Loading --> 
    <div id="customProgress" style="text-align:center;background:#FDFDFB;min-height:95vh">
      <img src="https://latuminggi.github.io/pdf.js_readonly/img/documentLoading.gif" /> 
    </div> 
    

    including adjustment in /js/viewer_noprint.js as you can see on this commit diff

  6. /generic/web/viewer_readonly.html
    to access file from query string (directly from URL)

    /generic/web/viewer_readonly.html?file={filename.pdf}
    

    For example: /generic/web/viewer_readonly.html?file=compressed.tracemonkey-pldi-09.pdf

    /generic/web/viewer_readonly.html?file={filename}
    

    For example: /generic/web/viewer_readonly.html?file=compressed.tracemonkey-pldi-09

    /generic/web/viewer_readonly.html?file={http(s)://example.com/filename(.pdf)}
    

    For example: /generic/web/viewer_readonly.html?file=https://latuminggi.github.io/pdf.js_readonly/generic/web/compressed.tracemonkey-pldi-09

B. Mobile

    NO Support for Password Protected PDF

  1. /mobile-viewer/viewer_readonly.html
    adjustment in viewer_readonly.html

    <!-- PDF.js Read Only Adjustment -->
    <!-- <script src="viewer.js"></script> --> <!-- you need to comment or remove this line -->
    <script src="viewer_mod.js"></script> <!-- adjust path to viewer_mod.js -->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script> <!-- adjust your jquery if necessary -->
    <script src="../js/pdf.js_mobile_readonly.js"></script> <!-- adjust path to pdf.js_mobile_readonly.js -->
    

    Note: if you want to enable cache canvas on mobile viewer, you can adjust these lines

    <!-- PDF.js Read Only Adjustment -->
    <!-- <script src="build/pdf.min.js"></script> --> <!-- use pdf(.min).js to enable cache canvas on mobile -->
    <script src="build/pdf_mod.min.js"></script> <!-- use pdf_mod(.min).js to disable cache canvas on mobile -->
    

    and if you want to access PDF file from different domain, makesure the PDF file webserver has HTTP Header Access-Control-Allow-Origin, allowing PDF.js viewer domain

    Access-Control-Allow-Origin: http(s)://yourPDFjsViewerDomain.here
    
  2. /js/pdf.js_mobile_readonly.js
    adjustment in pdf.js_mobile_readonly.js

    // Read Only Preferences
    var disableRghtClck = true; // Disable Right Click,   value: true || false
    var disableCopyText = true; // Disable Copy Text,     value: true || false
    var disableOpenFile = true; // Disable Open PDF,      value: true || false
    var disablePrintPdf = true; // Disable Print PDF,     value: true || false
    var disableDownload = true; // Disable Save PDF,      value: true || false
    var disablePrntScrn = true; // Disable Print Screen,  value: true || false (experimental)
    
  3. /mobile-viewer/viewer_mod.js
    modification from viewer.js
    there are 2 differences

    • first: To enable PDF large image size
    /*  Modified for PDF.js Read Only
     *  To enable PDF large image size
     */
    // const MAX_IMAGE_SIZE = 1024 * 1024; // Limited Max Image Size
    const MAX_IMAGE_SIZE = false; // Unlimited Max Image Size
    
    • second: To enable get query string of file or using default PDF file
    /*  Modified for PDF.js Read Only
     *  To enable get query string of file
     *  How can I get query string values in JavaScript? https://stackoverflow.com/a/901144/17754812
     */
    function getParameterByName(name, url = window.location.href) {
      name = name.replace(/[\[\]]/g, '\\$&');
      var regex   = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
          results = regex.exec(url);
      if (!results) return null;
      if (!results[2]) return '';
      return decodeURIComponent(results[2].replace(/\+/g, ' '));
    }
    
    /*  Modified for PDF.js Read Only
     *  To get query string of file or using default PDF file
     */
    // const DEFAULT_URL = "web/compressed.tracemonkey-pldi-09.pdf";
    // Get PDF file whether from "DEFAULT_URL" or "file" query string
    var file = getParameterByName('file');
    const DEFAULT_URL = (file === null || file === "") ? "web/compressed.tracemonkey-pldi-09" : file;
    

    Note: If you want to create viewer_mod.js on your own from viewer.js file of your current PDF.js version, make sure those lines above (or some codes like that) are adjusted.

  4. /mobile-viewer/build/pdf_mod.js
    modification from pdf.js

    if (this.cache[id] !== undefined) {
      /*  Modified for PDF.js Read Only
       *  To disable cache canvas on mobile
       */
      /* canvasEntry = this.cache[id]; */
      canvasEntry = this.canvasFactory.create(width, height);
      this.canvasFactory.reset(canvasEntry, width, height);
      canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0);
    }
    

    Note: If you want to create pdf_mod.js on your own from pdf.js file of your current PDF.js version, make sure those lines above (or some codes like that) are adjusted.

  5. /mobile-viewer/viewer_readonly.html
    adjustment in viewer_readonly.html for custom progress document loading

    <!-- PDF.js Read Only Adjustment --> 
    <!-- Custom Progress Document Loading --> 
    <div id="customProgress" style="text-align:center;background:#FFF;min-height:95vh"> 
      <img src="https://latuminggi.github.io/pdf.js_readonly/img/documentLoadingMobile.gif" width="100%" /> 
    </div> 
    

    including adjustment in /mobile-viewer/viewer_mod.js as you can see on this commit diff

  6. /mobile-viewer/viewer_readonly.html
    to access file from query string (directly from URL)

    /mobile-viewer/viewer_readonly.html?file=path_to/{filename.pdf}
    

    For example: /mobile-viewer/viewer_readonly.html?file=web/compressed.tracemonkey-pldi-09.pdf

    /mobile-viewer/viewer_readonly.html?file=path_to/{filename}
    

    For example: /mobile-viewer/viewer_readonly.html?file=web/compressed.tracemonkey-pldi-09

    /mobile-viewer/viewer_readonly.html?file={http(s)://example.com/filename(.pdf)}
    

    For example: /mobile-viewer/viewer_readonly.html?file=https://latuminggi.github.io/pdf.js_readonly/generic/web/compressed.tracemonkey-pldi-09

How To Protect PDF file(s) from Direct Access

A. Apache
RewriteEngine on 
# only allow from following domain(s):
RewriteCond %{HTTP_REFERER} !^http://(www\.)?example.com*$ [NC] 
RewriteRule \.(pdf)$ - [F]
B. Nginx
server {
  ...

  location ~* \.(pdf)$ {
    # only allow from following domain(s):
    valid_referers example.com www.example.com;

    if ($invalid_referer) {
      return 403;
    }
  }

  ...
}
C. PHP
<?php
$file = '/path/to/file.pdf';
// only allow if specific cookie(s) available, for example:
if ( isset( $_COOKIE['yourCookie'] ) && $_COOKIE['yourCookie'] === 'yourCookieValue' ) {
  // only allow from following domain(s), for example:
  if ( isset( $_SERVER['HTTP_REFERER'] ) && strpos( $_SERVER['HTTP_REFERER'], 'example.com' ) ) {
    if ( file_exists($file) ) {
      header('Access-Control-Allow-Origin: http(s)://example.com');
      /*  use HTTP header Content-Type application/octet-stream instead application/pdf
       *  this can avoid like IDM to sniff PDF file with mime type application/pdf
       *  and makesure the URL you create does NOT have .pdf extension in the end 
       */
      header('Content-Type: application/octet-stream');
      header('Content-Length: '. filesize($file));
      header('Cache-Control: no-cache');
      header('Pragma: no-cache');
      readfile($file);
      exit;
    }
  }
}