Printing with the ScriptX.Services API
Introduction
The ScriptX.Services API provides services for printing, paper and printer settings, license registration and print job management.
The provided APIs are simple to use over the HTTP transport using GET and POST methods. GET methods will return information such as configuration, POST methods result in an action at the server, for example applying a license or performing a print.
An OpenAPI (Swagger) specification is also available here which includes functionality to try out API calls to the MeadCo ScriptX.Services for Cloud server.
Any native facilities of the browser, for example XMLHttpRequest or Fetch API may be used to interact with the ScriptX.Services server or any javascript library that envelopes these facilities, for example Axios or jQuery.
Adding the printing of HTML, PDF or RAW content via ScriptX.Services to a page displayed in a browser requires three steps:
-
Connect to ScriptX.Services to apply the license for the page session (required for ScriptX.Services for Windows PC, for other ScriptX.Services does not entail a server connection but for consistency enables library code to store the service server URL and license to use).
-
If required, obtain printer defaults such as the available printers, default printer and available paper sizes etc. This step may be skipped if the printer to use is known (or always use the default printer) and all other settings can be set by known values.
-
POST the required values to the ScriptX.Services Print endpoint: api/v1/printHtml/print or api/v1/printPdf/print or api/v1/printDirect/print.
For illustration we will use the Fetch API with ES6 asynchronous code as this is relatively short code.
Module for interacting with ScriptX.Services
First is a module that provides wrappers on the Web API:
"./scriptxservices.js"
export { connectToService, getPrintingDefaults, printHtml, printPdf, waitForSpoolingComplete };
// 'private' connection data
//
let _serviceUrl = "";
let _licenseGuid = "";
// apiEndPoint
//
// construct and return url for api
//
function apiEndPoint(apiName) {
return _serviceUrl + "api/v1/" + apiName;
}
// sleep
// as it says on the tin.
function sleep(msecs) {
return new Promise(resolve => setTimeout(resolve, msecs));
}
// headers
//
// returns the http header including to authorize access to ScriptX.Services
//
function headers() {
return {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Basic ' + btoa(_licenseGuid + ':')
}
}
// parseResponse
//
// If the reponse from fetch is not ok, throw the text of the error
// If ok, return the json object delivered from the server.
//
async function parseResponse(response) {
if (!response.ok) {
throw Error(await response.text());
}
return await response.json();
}
// callService
//
async function callService(apiName, sMethod, msg) {
const response = await fetch(apiEndPoint(apiName), {
method: sMethod,
cache: 'no-cache',
headers: headers(),
body: msg ? JSON.stringify(msg) : null
});
return await parseResponse(response);
}
// applyPrintLicense
//
// Use the license on this page
//
// Returns the detail of the license if successful, or throws an error.
//
async function applyPrintLicense() {
return await callService('licensing', 'POST', {
"guid": _licenseGuid,
"url": "warehouse",
"revision": 0
});
}
// export: connectToService
//
// record server to use and apply the client license to this page
//
// Returns the detail of the license if successful, or throws an error.
//
async function connectToService(sServer, sLicenseGuid) {
_serviceUrl = sServer;
if (_serviceUrl.lastIndexOf("/") !== (_serviceUrl.length - 1)) {
_serviceUrl += "/";
}
_licenseGuid = sLicenseGuid;
return await applyPrintLicense();
}
// export: getPrintingDefaults
//
async function getPrintingDefaults() {
return await callService('printHtml/htmlPrintDefaults/0', 'GET');
}
// export: printHtml
//
async function printHtml(strHtml, printerName, pageSettings) {
try {
let response = await callService('printHtml/print', 'POST', {
contentType: 2, // "InnerHtml" - specifies an HTML fragment is to be printed
content: strHtml, // HTML fragment from page
device: {
printerName: printerName
},
settings: pageSettings
});
console.log("print started, status: " + response.status);
console.log(response);
return response;
}
catch (error) {
console.error("Error while printing: " + error);
}
return {};
}
// export: printPdf
//
async function printPdf(sPdfUrl, printerName) {
return await callService("printPdf/print", "POST", {
document: sPdfUrl,
device: {
printerName: printerName
},
settings: {
pageScaling: 2,
orientation: 2
}
});
}
// export: waitForSpoolingComplete
//
// pass in the response from printHtml/printPdf and await the job to complete
// spooling. Returns the final status and possible error message which could be reported to
// the user. printHtml/status works for both html and pdf prints (and visa-versa)
//
async function waitForSpoolingComplete(startJobResponse) {
let jobResponse = startJobResponse;
console.log("Start waitForSpoolingComplete on " +
startJobResponse.jobIdentifier + ", status: " + startJobResponse.status);
if (startJobResponse.status == 1 || startJobResponse.status == 2) {
do {
await sleep(500);
jobResponse = await callService("printHtml/status/" + startJobResponse.jobIdentifier, "GET");
console.log("Status now: " + jobResponse.status + ", " + jobResponse.message);
} while (jobResponse.status < 100 && jobResponse.status >= 0 && jobResponse.status != 6 );
}
return jobResponse;
}
UI binding code
directapi.js
import * as scriptxservices from "./scriptxservices.js"
(async () => {
try {
// connect to service and get default printer
const server = "http://127.0.0.1:41191"
const evaluationLicenseGUID = "3CFD70E2-F38F-4AB2-95F4-4CE4C1E39497";
const lic = await scriptxservices.connectToService(server, evaluationLicenseGUID);
console.log("License accepted");
console.log(lic);
const data = await scriptxservices.getPrintingDefaults();
console.log("print defaults obtained");
console.log(data);
// display some info
document.getElementById("defaultPrinter").textContent = data.device.printerName;
document.getElementById("buttonbar").style.display = "block";
document.getElementById("startup").style.display = "none";
// wire up UI - printHtml
document.getElementById("btn-print").addEventListener("click", async () => {
// print the html
let printResponse = await scriptxservices.printHtml(
document.getElementById("printContent").innerHTML,
data.device.printerName,
{
header: '',
footer: '',
page: {
units: 2, // mm
margins: { top: 12.5, left: 12.5, bottom: 12.5, right: 12.5 }
}
});
console.log("Printing html started.");
printResponse = await scriptxservices.waitForSpoolingComplete(printResponse);
console.log("Printing html completed.");
console.log(printResponse);
});
// wire up UI - printPdf
document.getElementById("btn-printpdf").addEventListener("click", async () => {
// print the pdf
let printResponse = await scriptxservices.printPdf(
"https://scriptxservices.meadroid.com/Content/Test1.pdf");
console.log("Printing pdf started.");
console.log(printResponse);
printResponse = await scriptxservices.waitForSpoolingComplete(printResponse);
console.log("Printing pdf completed.");
console.log(printResponse);
});
} catch (error) {
document.getElementById("errortext").innerText = "An error occured: " + error;
console.error("An error occured: " + error);
}
})();
The simple HTML document with UI glueing it all together
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Meadco's ScriptX Verification</title>
</head>
<body>
<div id="printContent">
<h1>No frills, no noise, example and verification of ScriptX Services
using the ScriptX.Services API</h1>
<h3>This example uses ScriptX.Services for Windows PC
in default configuration</h3>
<p>View console output for full API responses.
If no error occurs simple information and UI will appear below.</p>
</div>
<div id="startup" style="display:block">
Please wait .. starting .... <span id="errortext"></span>
</div>
<div id="buttonbar" style="display:none">
<div>Printing to: <span id="defaultPrinter"></span></div>
<br />
<div>
<button id="btn-print">Print document</button>
<button id="btn-printpdf">Print PDF</button>
</div>
</div>
<script type="module" src="directapi.js" async defer></script>
</body>
</html>
Seeing it in action
-
Download the latest version (2.22.1.18) of ScriptX.Services for Windows PC:
-
Run the downloaded installer.
In order for the installers to run, you must be logged on to your computer as an Administrator.
and then Try it.
More information is available on how to install ScriptX.Services For Windows PC.