This tutorial shows how to export a PDF document with annotations in the Document Viewer in an HTML5 JavaScript application using the LEADTOOLS SDK.
Overview | |
---|---|
Summary | This tutorial covers how to export a document in the LEADTOOLS Document Viewer to a PDF in an HTML5 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 working with annotations in the Document Viewer by reviewing the Add References and Set a License and Display Files in the Document Viewer tutorials, before working on the Save Annotations to PDF in the Document Viewer - 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 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 lib
folder and to import them in the index.html
file.
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, and the license set, coding can begin.
Open the index.html
file located in the project folder. Add the following lines in the <head>
tag to import the JS files and attach the dependencies to the index.html
page. Then add the following <select>
elements to the body of the index.html
page.
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DocumentViewer Example</title>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<!--Import LEADTOOLS Dependencies-->
<script src="./lib/Leadtools.js"></script>
<script src="./lib/Leadtools.Controls.js"></script>
<script src="./lib/Leadtools.Annotations.Engine.js"></script>
<script src="./lib/Leadtools.Annotations.Designers.js"></script>
<script src="./lib/Leadtools.Annotations.Rendering.Javascript.js"></script>
<script src="./lib/Leadtools.Annotations.Automation.js"></script>
<script src="./lib/Leadtools.ImageProcessing.Main.js"></script>
<script src="./lib/Leadtools.ImageProcessing.Color.js"></script>
<script src="./lib/Leadtools.ImageProcessing.Core.js"></script>
<script src="./lib/Leadtools.ImageProcessing.Effects.js"></script>
<script src="./lib/Leadtools.Document.js"></script>
<script src="./lib/Leadtools.Document.Viewer.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<!--Import Project Dependencies-->
<script src="app.js" type="text/javascript"></script>
</head>
<body>
<div class="container">
<div class="toolbar">
<div class="vcenter push-right">
<label for="interactiveSelect">Interactive mode:</label>
<select id="interactiveSelect"></select>
</div>
<div class="vcenter push-right">
<label for="annotationsSelect">Annotations objects:</label>
<select id="annotationsSelect"></select>
</div>
<div id="output" class="vcenter push-right"></div>
<div id="serviceStatus" class="vcenter push-right"></div>
<button id="saveAsPdf" class="vcenter push-right">Save as PDF</button>
</div>
<div class="docContainer">
<div class="sidepanel" id="thumbnails"></div>
<div class="centerpanel" id="viewer"></div>
<div class="sidepanel" id="bookmarks"></div>
</div>
</div>
</body>
Open the style.css
file located in the project folder. Remove the default body
styling and add the below lines of code to the body
.
/*
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;
flex-direction: row;
display: flex;
}
#bookmarks {
overflow: hidden;
}
.vcenter {
margin-top: auto;
margin-bottom: auto;
}
.hcenter {
margin-left: auto;
margin-right: auto;
}
.push-right {
margin-left: 10px;
}
.docContainer {
height: 95%;
width: 100%;
display: flex;
flex-direction: row;
}
.sidepanel {
width: 15%;
height: 100%;
}
.centerpanel {
width: 100%;
height: 100%;
}
#saveAsPdf {
height: 50%;
}
/* 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 located in the project folder.
Add the below code to create a DocumentViewer
object, add Automated Annotation support, load a default document, and export the document to PDF with the added annotations embedded.
window.onload = function () {
const licenseUrl = "https://demo.leadtools.com/licenses/js/LEADTOOLSEVAL.txt";
const developerKey = "EVAL";
lt.RasterSupport.setLicenseUri(licenseUrl, developerKey, function (setLicenseResult) {
// Check the status of the license
if (setLicenseResult.result) {
console.log("LEADTOOLS client license set successfully");
} else {
const msg = "LEADTOOLS License is missing, invalid or expired\nError:\n";
console.log(msg);
alert(msg);
}
});
let documentViewer = null;
class ViewerInitializer {
constructor(callback) {
this.callback = callback;
this.init();
}
static showServiceError = (jqXHR, statusText, errorThrown) => {
alert("Error returned from service. See the console for details.");
const serviceError = lt.Document.ServiceError.parseError(jqXHR, statusText, errorThrown);
console.error(serviceError);
};
init = () => {
this.initFactory();
this.testConnection();
};
initFactory = () => {
// To communicate with the DocumentService, it must be running!
// Change these parameters to match the path to the service.
lt.Document.DocumentFactory.serviceHost = "http://localhost:40000";
lt.Document.DocumentFactory.servicePath = "";
lt.Document.DocumentFactory.serviceApiPath = "api";
};
testConnection = () => {
const serviceStatus = document.getElementById("serviceStatus");
serviceStatus.innerHTML = "Connecting to service: " + lt.Document.DocumentFactory.serviceUri;
lt.Document.DocumentFactory.verifyService()
.done((serviceData) => {
serviceStatus.innerHTML = "Service connection verified!";
this.createDocumentViewer();
})
.fail((jqXHR, statusText, errorThrown) => {
serviceStatus.innerHTML = "Service connection unavailable.";
ViewerInitializer.showServiceError(jqXHR, statusText, errorThrown);
});
};
createDocumentViewer = () => {
// Initialize the user interface
const interactiveSelect = document.getElementById("interactiveSelect");
const panZoomOption = document.createElement("option");
panZoomOption.innerHTML = "Pan / Zoom";
panZoomOption.value = lt.Document.Viewer.DocumentViewerCommands.interactivePanZoom;
interactiveSelect.appendChild(panZoomOption);
const textOption = document.createElement("option");
textOption.value = lt.Document.Viewer.DocumentViewerCommands.interactiveSelectText;
textOption.innerHTML = "Select Text";
interactiveSelect.appendChild(textOption);
interactiveSelect.onchange = (e) => documentViewer.commands.run(e.target.value, null);
const annotationsSelect = document.getElementById("annotationsSelect");
const annSelectOption = document.createElement("option");
annSelectOption.innerHTML = "Select Annotations";
annSelectOption.value = lt.Annotations.Engine.AnnObject.selectObjectId.toString();
annotationsSelect.appendChild(annSelectOption);
const annLineOption = document.createElement("option");
annLineOption.innerHTML = "Line Object";
annLineOption.value = lt.Annotations.Engine.AnnObject.lineObjectId.toString();
annotationsSelect.appendChild(annLineOption);
const annRectOption = document.createElement("option");
annRectOption.innerHTML = "Rectangle Object";
annRectOption.value = lt.Annotations.Engine.AnnObject.rectangleObjectId.toString();
annotationsSelect.appendChild(annRectOption);
annotationsSelect.onchange = (e) => {
const value = +e.currentTarget.value;
documentViewer.annotations.automationManager.currentObjectId = value;
};
// Init the document viewer, pass along the panels
const createOptions = new lt.Document.Viewer.DocumentViewerCreateOptions();
// We are not going to use elements mode in this example
createOptions.viewCreateOptions.useElements = false;
createOptions.thumbnailsCreateOptions.useElements = false;
// The middle panel for the view
createOptions.viewContainer = document.getElementById("viewer");
// The left panel for the thumbnails
createOptions.thumbnailsContainer = document.getElementById("thumbnails");
// The right panel for the bookmarks
createOptions.bookmarksContainer = document.getElementById("bookmarks");
createOptions.useAnnotations = true;
// Create the document viewer
documentViewer = lt.Document.Viewer.DocumentViewerFactory.createDocumentViewer(createOptions);
// We prefer SVG viewing
documentViewer.view.preferredItemType = lt.Document.Viewer.DocumentViewerItemType.svg;
// Create html5 rendering engine
documentViewer.annotations.automationManager.renderingEngine = new lt.Annotations.Rendering.AnnHtml5RenderingEngine();
// Initialize documentViewer annotations
documentViewer.annotations.initialize();
documentViewer.annotations.automationManager.currentObjectIdChanged.add(function (sender, e) {
// When done drawing, the manager will return to the select object; so we need to force the annotationsSelect element to return to the select object option
annotationsSelect.value = sender.currentObjectId;
});
this.loadDefaultDoc(documentViewer, interactiveSelect);
};
loadDefaultDoc = (viewer, interactiveSelect) => {
// Load a PDF document
const url = "https://demo.leadtools.com/images/pdf/leadtools.pdf";
lt.Document.DocumentFactory.loadFromUri(url, null)
.done((doc) => {
const ready = () => {
viewer.setDocument(doc);
const panZoom = lt.Document.Viewer.DocumentViewerCommands.interactivePanZoom;
interactiveSelect.value = panZoom;
viewer.commands.run(panZoom, null);
if (this.callback) this.callback(viewer);
};
if (doc.isStructureSupported && !doc.structure.isParse) doc.structure.parse().done(ready).fail(ViewerInitializer.showServiceError);
else ready();
})
.fail(ViewerInitializer.showServiceError);
};
}
new ViewerInitializer();
$("#saveAsPdf").click(async function () {
documentViewer.prepareToSave();
await lt.Document.DocumentFactory.saveToCache(documentViewer.document);
const jobData = new lt.Document.DocumentConverterJobData();
jobData.documentFormat = lt.Document.Writer.DocumentFormat.pdf;
jobData.annotationsMode = lt.Document.DocumentConverterAnnotationsMode.embed;
let result = await documentViewer.document.convert(jobData);
promptSaveResult(result);
});
function promptSaveResult(result) {
const resultDocument = result.document != null ? result.document.url : result.archive.url;
const link = document.createElement("a");
const url = lt.Document.DocumentFactory.serviceUri + "/" + resultDocument;
link.href = url;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
};
Before running the front end HTML5/JS Document Viewer, 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 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, select an annotation object, draw on the document, then click Save as PDF
. Note that certain browsers may not show the embedded annotations.
This tutorial showed how to embed the annotations into a PDF file in a HTML5 JavaScript application.