This tutorial shows how to load, edit, and save PDF files that are PDF Form Field compatible using the HTML5/JS Document Viewer.
Overview | |
---|---|
Summary | This tutorial covers loading, editing, and exporting PDF form field compatible PDF files in a JavaScript application. |
Completion Time | 20 minutes |
Visual Studio Project | Download tutorial project (4 KB) |
Platform | JS Web Application |
IDE | Visual Studio Code - Client |
Development License | Download LEADTOOLS |
Get familiar with the basic steps of creating a project and loading files into the Document Viewer by reviewing the Add References and Set a License - HTML5 JavaScript and Display Files in the Document Viewer - HTML5 JavaScript tutorials, before working on the Load, Edit, and Export PDF Form Field Compatible PDF Files - HTML5 JavaScript tutorial.
This tutorial makes use of http-server
, a console command for running a static file server. To install http-server
first install Node.js
and then install http-server
.
Start with a copy of the project created in the Display Files in the Document Viewer - HTML5 JavaScript tutorial. If that project is unavailable, follow the steps in that tutorial to create it.
The references needed depend upon the purpose of the project. References can be added by .js
files located at <INSTALL_DIR>\LEADTOOLS23\Bin\JS
.
For this project, the following references are needed:
Leadtools.js
Leadtools.Annotations.Automation.js
Leadtools.Annotations.Designer.js
Leadtools.Annotations.Engine.js
Leadtools.Annotations.Rendering.JavaScript.js
Leadtools.Controls.js
Leadtools.Document.js
Leadtools.Document.Viewer.js
Leadtools.ImageProcessing.Main.js
Leadtools.ImageProcessing.Color.js
Leadtools.ImageProcessing.Core.js
Leadtools.ImageProcessing.Effects.js
Make sure to copy these files to the project's lib
folder.
For a complete list of which JS files are required for your application, refer to Files to be Included with your Application.
The License unlocks the features needed for the project. It must be set before any toolkit function is called. For details including tutorials for different platforms, refer to Setting a Runtime License.
There are two types of runtime licenses:
With the project created, dependencies added, the license set, and the load file code added, coding can begin.
Open the index.html
file located in the project folder and add the following lines in the .toolbar
div:
<button class="button" id="loader">Load File</button>
<button class="button" id="getData">Display Field Data in Console</button>
<button class="button" id="export">Export PDF</button>
Adding these buttons will allow the user to load PDF files, display the form field values, and export changes made to the PDF file.
Lastly, add this line above the ending </div>
tag line in order to "house" our PDF file when exporting it:
<iframe id="parent"></iframe>
The section should look like below:
<body>
<div class="container">
<div class="toolbar">
<button class="button" id="loader">Load File</button>
<button class="button" id="getData">Display Field Data in Console</button>
<button class="button" id="export">Export PDF</button>
</div>
<div class="docContainer">
<div id="documentViewer"></div>
</div>
<iframe id="parent"></iframe>
</div>
</body>
Open the styles.css
file and add the following CSS styling.
/*
Remove default body styling.
Set the body to flex as a column;
*/
body {
margin: 0;
display: flex;
flex-direction: column;
}
.container {
margin: 10px;
width: calc(100% - 20px);
height: calc(100vh - 20px);
}
.toolbar {
height: 5%;
width: 100%;
border-bottom: 2px solid #333;
display: block;
text-align: center;
}
.button {
padding-left: 2%;
padding-right: 2%;
width: 20%;
margin-right: 2%;
text-align: center;
height: 40px;
}
.docContainer {
height: 95%;
width: 100%;
display: flex;
flex-direction: row;
}
#documentViewer {
height: 95%;
width: 100%;
display: flex;
flex-direction: row;
}
#parent {
position: absolute;
left: -10000px;
width: 1px;
height: 1px;
overflow: hidden;
}
/* Styles for Elements Mode. */
.lt-item,
.lt-image-border {
/* Box Shadow (view, item, image border) */
box-shadow: #333 2px 2px 5px 1px;
}
.lt-view,
.lt-thumb-item {
/* View */
margin: 5px;
padding: 5px;
}
.lt-item {
/* Item */
border: 2px solid #6ecaab;
background-color: #b2decf;
padding: 10px;
}
.lt-image-border {
/* Image Border */
border: 3px solid #444;
background-color: white;
}
.lt-thumb-item {
/* Thumbnail Item */
border: 2px solid #6ecaab;
background-color: #b2decf;
}
.lt-thumb-item.lt-thumb-item-selected {
/* Selected Thumbnail Item */
border: 2px solid #59b2ba;
background-color: #8ce1e1;
}
.lt-thumb-item-hovered {
/* Hovered Thumbnail Item */
border: 2px solid #52b996;
background-color: #87c7b1;
}
.small-modal {
max-width: 200px;
width: 200px;
}
Open the app.js
file that is located in the project folder.
Be sure to have this first line at the top of the JS file so that the documentViewer
object can be accessed:
let documentViewer = null;
Add the code below to initialize the DocumentViewer
object, set up connections to the document service, and also to enable the buttons for the tutorial. This will load a non-compatible PDF file initially.
window.onload = async () => {
// Set the LEADTOOLS Evaluation license
const licenseUrl = "./Leadtools/LEADTOOLS.lic.txt";
const developerKey = "ADD THE CONTENTS OF THE LEADTOOLS.lic.key.txt FILE";
lt.RasterSupport.setLicenseUri(licenseUrl, developerKey, null);
// Create the options object for the DocumentViewer
const createOptions = new lt.Document.Viewer.DocumentViewerCreateOptions();
createOptions.viewCreateOptions.useElements = true;
// Set viewContainer to #documentViewer
createOptions.viewContainer = document.getElementById("documentViewer");
// Create the document viewer
documentViewer = lt.Document.Viewer.DocumentViewerFactory.createDocumentViewer(createOptions);
// Set interactive mode to Pan / Zoom
//documentViewer.commands.run(lt.Document.Viewer.DocumentViewerCommands.interactivePanZoom);
// We prefer SVG viewing over Image viewing for this example
documentViewer.view.preferredItemType = lt.Document.Viewer.DocumentViewerItemType.svg;
// To use Image: lt.Document.Viewer.DocumentViewerItemType.image;
//documentViewer.view.imageViewer.autoCreateCanvas = true;
documentViewer.annotations.automationManager.renderingEngine = new lt.Annotations.Rendering.AnnHtml5RenderingEngine();
// Initialize documentViewer annotations
documentViewer.annotations.initialize();
// Before we call the service, we need to explain where it is ("localhost:40000/api", for example):
lt.Document.DocumentFactory.serviceHost = "http://localhost:40000"; // or wherever your host is
lt.Document.DocumentFactory.servicePath = ""; // the path to the root of the service, which is nothing for this example
lt.Document.DocumentFactory.serviceApiPath = "api"; // Routing occurs at "/api", unless you change the routing in the DocumentService
//Initialize the onclick events for our two buttons
document.getElementById('loader').onclick = selectAndLoadFile;
document.getElementById('getData').onclick = getData;
document.getElementById('export').onclick = exportPDF;
// Load a PDF document
const url = "https://demo.leadtools.com/images/pdf/leadtools.pdf";
const loadDocumentOptions = new lt.Document.LoadDocumentOptions();
loadDocumentOptions.loadFormFieldsMode = 1;
// Call the "LoadFromUri" and pass success and failure callbacks to the promise
try {
let document = await lt.Document.DocumentFactory.loadFromUri(url, loadDocumentOptions)
documentViewer.setDocument(document);
if (document.formFields.hasFormFields) {
console.log("This document has PDF Form Fields. Click the 'Display Field Data in the Console' to see more information")
} else {
console.log("This document does not have PDF Form Fields")
}
} catch (error) {
console.error(error);
// Get more information from LEADTOOLS
let serviceError = lt.Document.ServiceError.parseError(jqXHR, statusText, errorThrown);
lt.LTHelper.log(serviceError);
// Show an alert about what the issue is
let lines = [];
lines.push("Document Viewer Error:");
lines.push(serviceError.message);
lines.push(serviceError.detail);
lines.push("See console for details.")
alert(lines.join("\n"));
}
}
Next add two new functions named selectAndLoadFile
and exportPDF
which will be used to load a specified PDF file and export it when finished. Add the respective code below:
function selectAndLoadFile() {
//creates an input element on the Import Document button to upload files
//into the document editor
const input = document.createElement('input');
input.type = 'file';
input.style.display = 'none';
input.accept = '.doc, .docx, .pdf, .rtf, .txt';
input.onchange = async function (e) {
let files = input.files;
if (!files?.length)
return;
let file = files[0];
//Set the cursor to an idle animations
document.body.style.cursor = 'wait';
//Create the document loading options
const loadDocumentOptions = new lt.Document.LoadDocumentOptions();
loadDocumentOptions.loadFormFieldsMode = 1;
try {
//load the document from a file using the options
let doc = await lt.Document.DocumentFactory.loadFromFile(file, loadDocumentOptions)
//set the new document in the document viewer
documentViewer.setDocument(doc);
//check to see if the document has form fields
if (doc.formFields.hasFormFields) {
console.log("This document has PDF Form Fields. Click the 'Display Field Data in the Console' to see more information")
}
else {
console.log("This document does not have PDF Form Fields")
}
} catch (error) {
console.error(error);
}
//return the cursor to default
document.body.style.cursor = 'default';
};
input.click();
}
async function exportPDF() {
try {
//gets the document in the document viewer
let doc = await documentViewer.document;
//prepares the document for saving
documentViewer.prepareToSave();
//saves the document to the cache
lt.Document.DocumentFactory.saveToCache(doc)
//once the doc is saved to the cache, creates the printing option
const options = new lt.Document.Viewer.PrintDocumentOptions();
//certain printing options are being set
options.showAnnotations = true;
options.usePdfPrinting = true;
//gets the iframe HTMLElement that will "house" the printable pdf
options.parent = document.getElementById('parent');
//prints and opens the browser printer for saving/printing
documentViewer.print(options);
} catch (error) {
console.error(error);
}
}
Lastly, add another function named getData
which will display all the form field data to the console (this can be viewed in your browsers DevTools).
function getData() {
let doc = documentViewer.document;
documentViewer.prepareToSave();
if (doc.formFields.hasFormFields) {
let containers = doc.formFields.getFormFields();
for (let i = 0; i < containers.length; i++) {
for (let j = 0; j < containers[i].children.count; j++) {
console.log(`-------------------------- Page ${i + 1} - Field ${j + 1} ---------------------------------`)
console.log(`ID: ${containers[i].children.item(j).id}`);
console.log(`Name: ${containers[i].children.item(j).name}`);
console.log(`Bounds: ${containers[i].children.item(j).bounds}`);
console.log(`Background color: ${containers[i].children.item(j).backgroundColor}`);
console.log(`Printable: ${containers[i].children.item(j).printable}`);
console.log(`Viewable: ${containers[i].children.item(j).viewable}`);
console.log(`Locked: ${containers[i].children.item(j).locked}`);
console.log(`Required: ${containers[i].children.item(j).required}`);
console.log(`Read Only: ${containers[i].children.item(j).readOnly}`);
console.log(`Border Style: ${containers[i].children.item(j).borderStyle.style}`);
console.log(`Border Color: ${containers[i].children.item(j).borderStyle.color}`);
console.log(`Border Width: ${containers[i].children.item(j).borderStyle.width}`);
console.log(`Font Name: ${containers[i].children.item(j).textStyle.fontName}`);
console.log(`Font Size: ${containers[i].children.item(j).textStyle.fontSize}`);
console.log(`Font Color: ${containers[i].children.item(j).textStyle.color}`);
console.log(`Font Alignment: ${containers[i].children.item(j).textStyle.textAlignment}`);
console.log(`Type: ${containers[i].children.item(j).type}`);
if (containers[i].children.item(j).type == "DocumentTextFormField") {
console.log(`Value: ${containers[i].children.item(j).value}`)
console.log(`Content Type: ${containers[i].children.item(j).contentType}`);
console.log(`Max Length: ${containers[i].children.item(j).maxLength}`)
console.log(`Multi-Line: ${containers[i].children.item(j).multiline}`)
console.log(`Password: ${containers[i].children.item(j).isPassword}`)
console.log(`Comb: ${containers[i].children.item(j).isComb}`)
}
if (containers[i].children.item(j).type == "DocumentChoiceFormField") {
console.log(`Options Display Value: ${containers[i].children.item(j).optionsDisplayValue}`)
console.log(`Options Exported Value: ${containers[i].children.item(j).optionsExportedValue}`);
console.log(`Selected Indices: ${containers[i].children.item(j).selectedIndices}`)
console.log(`Multi-Select: ${containers[i].children.item(j).multiSelect}`)
console.log(`Choice Type: ${containers[i].children.item(j).choiceType}`)
}
if (containers[i].children.item(j).type == "DocumentButtonFormField") {
console.log(`Checked: ${containers[i].children.item(j).isChecked}`)
if (containers[i].children.item(j).buttonType == 0) {
console.log(`Button Type: Check Box`);
} else {
console.log(`Button Type: Radio Button`);
}
}
}
}
}
else {
console.log("This document does not have PDF Form Fields")
}
}
Before running the front-end HTML5/JS Document Viewer, you must run the Document Service. The LEADTOOLS SDK installation provides three examples of the Document Service for the following platforms:
For instructions on how to set up and configure the Document Service, in the three platforms previously listed, refer to the steps in the Get Started with the Document Viewer Demo - HTML5 JavaScript tutorial.
For the purposes of this tutorial, the .NET Framework Document Service is used and it can be found here: <INSTALL_DIR>\LEADTOOLS23\Examples\Document\JS\DocumentServiceDotNet\fx
.
Once you have the back-end Document Service running, open the Command Line and cd
into the project folder. Use the following command to run a static file server: http-server
The server should start and run on http://localhost:8080
. A message should appear in the console indicating all the ports that the server is available on.
To test, follow the steps below:
This tutorial showed how to load, edit, and save a PDF form field compatible file in an HTML5/JS Document Viewer application.