Create a Custom PDF Viewer With PDF.js and Restrict Downloading & Printing


Create a Custom PDF Viewer

Demo Download

In this tutorial, I will create a custom PDF viewer with PDF.js, which will restrict users to download and print PDF file.

This is often required by many PDF books sellers who let the user to read their PDF books online on their websites but do not allow user to download or print their PDF file without making a certain payment of that PDF file or book.

Whenever you view any PDF file on any web browser such as Google Chrome, Mozilla Firefox, IE, Opera, Safari and etc. They all uses their custom PDF file viewer which allow user to download PDF file and also print those PDF files easily.

There are several paid solution available to this problem but I will share a way in which you can resolve the issue without making any payment.

PDF.js is the most useful library which will allow me to achieve my goal of creating a custom PDF viewer with JavaScript with read only feature.

I will also create a Next and Previous button which will allow me to move to next or previous page of PDF file.

I will also display the current and total pages of PDF file on the same custom PDF viewer on the top right side.

Steps to Create a Custom PDF Viewer With JavaScript

I will follow the below steps to create a custom PDF viewer with JavaScript through PDF.js.

  1. Create an index.php for PDF viewer
  2. Add HTML for PDF viewer
  3. Add CSS for navigation and view of PDF viewer
  4. Add PDF.js library and JavaScript
  5. Add PHP in header to configure the CORS
  6. Create .htaccess file to revoke direct PDF file access via URL

1. Create an index.php for PDF viewer

First of all create an index.php file which will act as PDF viewer file. Once the file is created I will add HTML, CSS, PDF.js and PHP code in it.

2. Add HTML for PDF viewer

Add the below HTML code for PDF viewer, pagination of Next, Previous buttons, current and total number of pages.

<div class="pagination">
    <div class="wrap">
        <button id="prev">Previous</button>
        <button id="next">Next</button>
        &nbsp; &nbsp;
        <span>Page: <span id="page_num"></span> / 
        <span id="page_count"></span></span>
    </div>
</div>

<canvas id="the-canvas"></canvas>

3. Add CSS for navigation and view of PDF viewer

Add the below CSS to style your PDF viewer.

body{
    background: black;
    margin:0px;
    }
.pagination{
    background: #ffffff;
    width: 100%;
    float: left;
}
.pagination .wrap{
    float:right;
    width: 300px;
} 
#the-canvas {
    border: 1px solid black;
    direction: ltr;
    margin: 0 auto;
    display: block;
}
@media print {
  body {display:none;}
}

4. Add PDF.js library and JavaScript

Now, it is the time to add the PDF.js library and add required JavaScript to make it functional.

<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<script>
// Disable Canvas Image Downloading    
document.addEventListener('contextmenu', event => event.preventDefault());

// If absolute URL from the remote server is provided, configure the CORS
// header on that server.
var url = '<?php echo $pdf_file;?>'; // your file location and file name with ext.


// Loaded via <script> tag, create shortcut to access PDF.js exports.
var pdfjsLib = window['pdfjs-dist/build/pdf'];

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

var pdfDoc = null,
    pageNum = 1,
    pageRendering = false,
    pageNumPending = null,
    scale = 2,
    canvas = document.getElementById('the-canvas'),
    ctx = canvas.getContext('2d');

/**
 * Get page info from document, resize canvas accordingly, and render page.
 * @param num Page number.
 */
function renderPage(num) {
  pageRendering = true;
  // Using promise to fetch the page
  pdfDoc.getPage(num).then(function(page) {
    var viewport = page.getViewport({scale: scale});
    canvas.height = viewport.height;
    canvas.width = viewport.width;

    // Render PDF page into canvas context
    var renderContext = {
      canvasContext: ctx,
      viewport: viewport
    };
    var renderTask = page.render(renderContext);

    // Wait for rendering to finish
    renderTask.promise.then(function() {
      pageRendering = false;
      if (pageNumPending !== null) {
        // New page rendering is pending
        renderPage(pageNumPending);
        pageNumPending = null;
      }
    });
  });

  // Update page counters
  document.getElementById('page_num').textContent = num;
}

/**
 * If another page rendering in progress, waits until the rendering is
 * finised. Otherwise, executes rendering immediately.
 */
function queueRenderPage(num) {
  if (pageRendering) {
    pageNumPending = num;
  } else {
    renderPage(num);
  }
}

/**
 * Displays previous page.
 */
function onPrevPage() {
  if (pageNum <= 1) {
    return;
  }
  pageNum--;
  queueRenderPage(pageNum);
}
document.getElementById('prev').addEventListener('click', onPrevPage);

/**
 * Displays next page.
 */
function onNextPage() {
  if (pageNum >= pdfDoc.numPages) {
    return;
  }
  pageNum++;
  queueRenderPage(pageNum);
}
document.getElementById('next').addEventListener('click', onNextPage);

/**
 * Asynchronously downloads PDF.
 */
pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
  pdfDoc = pdfDoc_;
  document.getElementById('page_count').textContent = pdfDoc.numPages;

  // Initial/first page rendering
  renderPage(pageNum);
});
</script>

5. Add PHP in header to configure the CORS

Everything is ready now but it will not work because of Cross-Origin Resource Sharing (CORS) issue. Therefore, I will add the below PHP code to resolve the CORS issue in the top of index.php file.

// Allow from any origin
if (isset($_SERVER['HTTP_ORIGIN'])) {
    // should do a check here to match $_SERVER['HTTP_ORIGIN'] to a
    // whitelist of safe domains
    header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
    header('Access-Control-Allow-Credentials: true');
    header('Access-Control-Max-Age: 86400');    // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {

    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
        header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");         

    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
        header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");

}

if(!isset($_GET['pdf_file']) || empty($_GET['pdf_file'])){
      header("Location: error.php");
      exit();
    }else{
      $pdf_file = $_GET['pdf_file'];
    }

The above code also getting the PDF file name through $_GET[] super global variable. If it is an empty then you can not view the PDF file, file name must be available to read the file on server therefore the URL must contain pdf_file parameter, for example like below URL.

https://www.allphptricks.com/demo/2022/apr/custom-pdf-viewer/index.php?pdf_file=sample-file1.pdf

6. Create .htaccess file to revoke direct PDF file access via URL

This is the most important step, although the application is ready but user can still access the PDF file directly hitting the below URL in the browser.

https://www.allphptricks.com/demo/2022/apr/custom-pdf-viewer/sample-file1.pdf

Therefore, I will add some code that will revoke direct PDF file access via URL like above.

# Simple File List Access Restricter

RewriteEngine On

# 1) If NOT the current host
RewriteCond %{HTTP_HOST}@@%{HTTP_REFERER} !^([^@]*)@@https?://\1/.*

# 2) Deny access to these types
RewriteRule \.(gif|jpg|jpeg|png|tif|pdf|wav|wmv|wma|avi|mov|mp4|m4v|mp3|zip?)$ - [F]

Save the above file with .htaccess and placed it in the same folder where PDF files exist.

Conclusion

By following the above steps, you can easily create your custom PDF file viewer using JavaScript and PDF.js library.

I hope this will solve your issue and help you to achieve your desired goal to restrict PDF files downloading and printing.

Demo Download

If you found this tutorial helpful, share it with your friends and developers group.

I spent several hours to create this tutorial, if you want to say thanks so like my page on Facebook, Twitter and share it.

Facebook Official Page: All PHP Tricks

Twitter Official Page: All PHP Tricks

Article By
Javed Ur Rehman is a passionate blogger and web developer, he loves to share web development tutorials and blogging tips. He usually writes about HTML, CSS, JavaScript, Jquery, Ajax, PHP and MySQL.
  1. Hi Ulrich,
    I’ve been using your example in projects, works perfect, but recently this viewer is broken, I see that also your example is broken, any idea what could causing this?

  2. Hello. Sounds like what I have been looking for, but I’m a dummy, I don’t code.
    Where can I find someone to implement this for me. My mother passed away. She used to publish newsletters on how to grow cactus plants. I need a PDF embedder to put her journals online so they can’t be printed or downloaded. Thanks.

  3. thanks sir above example was very useful. but i am trying to annotate the pdf and store only annotation in database and when same file is accessed the stored annotation should be applied to it.

    Please can you help in this regard I am using php and mysql and pdfjs

    1. Dear Raghavendra, my tutorial is just to display the PDF on browser, but you can not edit the PDF with this tutorial, adding annotate to PDF is like editing PDF which is not possible with this tutorial.

  4. Great work and thank you.
    It displays A4 pdf OK but when I tried a office365 excel pdf in A3 form it goes off the screen and it needs the scrolling bars. Would it be possible to display A3 in just the screen size.
    Thanks again and sorry to ask
    Phil

  5. Great tutorial, thank you for sharing.

    I have noticed that no URLs are active and cannot be clicked to open the URL?

    How do you allow URL’s to be clicked and opened in browser?

    Cheers!

  6. Hi Javed,
    This is a great project. Thank you for producing it. I have a real
    need to apply this on my website but I am having a problem getting
    the code to work. I am probably doing something wrong. Here’s the
    string I am trying to use to start the viewer.
    No matter what I try it just doesn’t work. Can you tell me why the viewer does not get the
    input file name to load the PDF. The viewer box displays but not the
    PDF. Any help would really be appreciated. Thank you.

  7. Interesting project. Seems to work well.

    Is there a way to display the zoom button? Can you re-flow the page to fit the viewport, without shrinking it (make a standard 8 1/2″ x 11″ page fit legibly on a smaller screen/device)?

    Thanks….Rick..

    1. Hi Rick, thanks for your input. I tried to explain this example as simple as possible. However, you can do modification as per your need. Just read out the documentation of PDF.js.

  8. You have simply disabled java script in the browser so it can not be copied or downloaded.

  9. Hi Javed, that’s great. So many thanks for all your tutorials!
    Do you have something similar for restrict downloading images?
    Have a nice day!

Leave a Reply

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