How To Create An Angular Form Array
December 5, 2022Design Patterns In Software Development
January 9, 2023
In this blog, I’ll be going over creating a basic custom PDF viewer by using PDF.js. I came across this package while working on a project that required learning material to be displayed but also to prevent the user from downloading the document itself. Please note that this is not a 100% guaranteed way of protecting your PDF content, however it does make it slightly harder for your users to download the document itself.
Now lets get setup:
Step 1)
If you are wanting more information on the PDF.js library you can checkout their documentation.
You can set this up by using your node package manager, however for my example for this blog I’m going to make use of one of the CDN(s) that are being hosted currently which can be found in the documentation of the PDF.js package.
Here is the CDN I used within my head tag.
<script src="//mozilla.github.io/pdf.js/build/pdf.js"></script>
Step 2)
Then in your body we will need a canvas tag to view our PDF file from. This is the canvas tag I created along with some buttons to help us control which page we will be looking at.
<body> <div> <button id="prev">Previous</button> <button id="next">Next</button> <span>Page: <span id="page_num"></span> / <span id="page_count"></span></span> </div> <canvas id="the-canvas"></canvas> </body>
Step 3)
Now that we have the HTML part down we can start adding the scripts to initialize the content to be shown inside the canvas tag.
<script id="script"> // Here you can define what PDF you will be using to be displayed in the canvas var url = 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf'; // 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 = '//mozilla.github.io/pdf.js/build/pdf.worker.js'; var pdfDoc = null, pageNum = 1, pageRendering = false, pageNumPending = null, scale = 1.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>
Output
In the above code snippets I used exactly the same setup as what was provided on the documentation. Its that easy to get yourself all setup.
Now you should have a page that looks like this.
Lets prevent the user from downloading your content
You might have already noticed the issue here… If you right click you can still save as image. Do not worry my paranoid friend, there is a very simple one liner that we can use to prevent this from happening. If you add the following to your script you will no longer have this issue.
document.getElementById('the-canvas').addEventListener('contextmenu', event => event.preventDefault());
The rest is up to you on how you want it all to look.
Upcoming blog information
In my next upcoming blog I’ll cover the default PDF viewer that PDF.js provides.
In case you want an idea of what I’m talking about go here.
Conclusion
I am by no means good at PDF.js, I have only started looking into this recently for one of my current projects and I thought it would make a great blog post. I hope this helped you understand things a bit better on how you can make use of the PDF.js.