How to Open a Password Protected PDF with Javascript using PDF.JS

javascript
Published on December 14, 2016

In PDF.JS Tutorial 1 we discussed how PDF.JS can be used to show a preview of the PDF at upload time. The application can navigate pages of the PDF using PDF.JS APIs.

PDF.JS being a complete PDF viewer also supports viewing of password protected PDFs. This means that your application can prompt the user for password of the PDF when trying to be viewed. On receiving the correct password the application can show the PDF to the user, or else show an error message.

This tutorial is an extension of Tutorial 1. It uses the same demo application that was used in that tutorial.

Demo

Click on the button below to choose a PDF file :

Loading document ...
Page
of
Loading page ...

If you want a sample password protected PDF, you can download it from here.
Codes for the demo are provided towards the end of this tutorial for download.

Viewing a Password Protected PDF

To open a password protected PDF with PDF.JS, pass a password parameter to the PDFJS.getDocument API call :

PDFJS.getDocument({ url: pdf_url, password: pdf_password })

You can catch the error when the user gives the incorrect password.

PDFJS.getDocument({ url: pdf_url, password: pdf_password }).then(function(pdf_doc) {
	// success
}).catch(function(error) {
	// incorrect password

	// error is an object having 3 properties : name, message & code
});

For normal PDFs that have no passwords you can pass an empty string as the password.

That's it. For opening a password protected PDF only this addition is required.

HTML of the Demo Application

<button id="upload-button">Select PDF</button> 
<input type="file" id="file-to-upload" accept="application/pdf" />

<div id="pdf-main-container">
    <div id="pdf-loader">Loading document ...</div>
    <div id="password-container">
		<input type="password" id="pdf-password" autocomplete="off" placeholder="Password" /><button id="submit-password">Submit</button>
		<div id="password-message"></div>
	</div>
    <div id="pdf-contents">
        <div id="pdf-meta">
            <div id="pdf-buttons">
                <button id="pdf-prev">Previous</button>
                <button id="pdf-next">Next</button>
            </div>
            <div id="page-count-container">Page <div id="pdf-current-page"></div> of <div id="pdf-total-pages"></div></div>
        </div>
        <canvas id="pdf-canvas" width="400"></canvas>
        <div id="page-loader">Loading page ...</div>
    </div>
</div>

PDF.JS Tutorial 1 explains the HTML of the demo application in detail. The only addition is #password-container which holds the textbox where the user shall type the password.

Javascript in the Demo Application

Again see PDF.JS Tutorial 1 for the explanation of the Javascript. It is almost the same, the only difference being the password handling feature.

var __PDF_DOC,
	__CURRENT_PAGE,
	__TOTAL_PAGES,
	__PAGE_RENDERING_IN_PROGRESS = 0,
	__CANVAS = $('#pdf-canvas').get(0),
	__CANVAS_CTX = __CANVAS.getContext('2d');

// Initialize and load the PDF
function showPDF(pdf_url, password) {
	$("#pdf-loader").show();
	$("#password-container").hide();
	
	PDFJS.getDocument({ url: pdf_url, password: password }).then(function(pdf_doc) {
		__PDF_DOC = pdf_doc;
		__TOTAL_PAGES = __PDF_DOC.numPages;
		
		// Hide the pdf loader and show pdf container in HTML
		$("#pdf-loader").hide();
		$("#password-container").hide();
		$("#pdf-contents").show();
		$("#pdf-total-pages").text(__TOTAL_PAGES);

		// Show the first page
		showPage(1);
	}).catch(function(error) { console.log(error)
		$("#pdf-loader").hide();
		
		if(error.name == 'PasswordException') {
			$("#password-container").show();
			$("#pdf-password").val('');
			$("#password-message").text(error.code == 2 ? error.message : '');
		}
		else {
			$("#upload-button").show();
			alert(error.message);
		}
	});
}

// Load and render a specific page of the PDF
function showPage(page_no) {
	__PAGE_RENDERING_IN_PROGRESS = 1;
	__CURRENT_PAGE = page_no;

	// Disable Prev & Next buttons while page is being loaded
	$("#pdf-next, #pdf-prev").attr('disabled', 'disabled');

	// While page is being rendered hide the canvas and show a loading message
	$("#pdf-canvas").hide();
	$("#page-loader").show();

	// Update current page in HTML
	$("#pdf-current-page").text(page_no);
	
	// Fetch the page
	__PDF_DOC.getPage(page_no).then(function(page) {
		// As the canvas is of a fixed width we need to set the scale of the viewport accordingly
		var scale_required = __CANVAS.width / page.getViewport(1).width;

		// Get viewport of the page at required scale
		var viewport = page.getViewport(scale_required);

		// Set canvas height
		__CANVAS.height = viewport.height;

		var renderContext = {
			canvasContext: __CANVAS_CTX,
			viewport: viewport
		};
		
		// Render the page contents in the canvas
		page.render(renderContext).then(function() {
			__PAGE_RENDERING_IN_PROGRESS = 0;

			// Re-enable Prev & Next buttons
			$("#pdf-next, #pdf-prev").removeAttr('disabled');

			// Show the canvas and hide the page loader
			$("#pdf-canvas").show();
			$("#page-loader").hide();
		});
	});
}

// Upon click this should should trigger click on the <input type="file" /> element
// This is better than showing the not-good-looking file input element
$("#upload-button").on('click', function() {
	$("#file-to-upload").trigger('click');
});

// When user chooses a PDF file
$("#file-to-upload").on('change', function() {
	// Validate whether PDF
    if(['application/pdf'].indexOf($("#file-to-upload").get(0).files[0].type) == -1) {
        alert('Error : Not a PDF');
        return;
    }

	$("#upload-button").hide();

	// Send the object url of the pdf
	showPDF(URL.createObjectURL($("#file-to-upload").get(0).files[0]), '');
});

$("#submit-password").on('click', function() {
	showPDF(URL.createObjectURL($("#file-to-upload").get(0).files[0]), $("#pdf-password").val());
});

// Previous page of the PDF
$("#pdf-prev").on('click', function() {
	if(__CURRENT_PAGE != 1)
		showPage(--__CURRENT_PAGE);
});

// Next page of the PDF
$("#pdf-next").on('click', function() {
	if(__CURRENT_PAGE != __TOTAL_PAGES)
		showPage(++__CURRENT_PAGE);
});

Download Sample Codes

Download
In this Tutorial