I would like to print on a thermal printer from a random list of images but I don't know how.
Currently I have a touchscreen on which I just press a button and it prints an image already defined.
In what language should I write it? Can anyone help me? :D
Actually i have this code :
/**
* Simple printer application example.
*
* This application creates areas that when clicked print a document.
* During the printing, all the areas are disabled and are enabled
* only a short time after the print is over (monkey countermeasure).
* When the printer is offline, the area are also not enabled.
*
* The buttons definitions are defined in a JSON file containing an array of ButtonSpec.
*/
function SimplePrinterApp() {
this.printer = null;
this.jobid = -1;
this.container = null;
this.printAllow = false;
this.afterPrintTimeout = 2000;
this.isOpen = undefined;
this.date = null;
this.dayPrintCounter = 0;
this.totalPrintCounter = 0;
this.clickDisabled = false;
}
SimplePrinterApp.prototype = {
/**
* Initialize the application
* @param {String} url is the URL containing the buttons data (a JSON file)
*/
initialize: function(url) {
this.container = document.getElementById("button-container");
this.body = document.getElementById("body");
this.mayBeEraseLastPrint();
this.fetchConfiguration(url);
},
loadLastPrint: function() {
var lastPrint = localStorage.getItem('lastPrint');
var limit = this.config.printlimit;
if (lastPrint) {
var today = this.getTodayDate();
var data = lastPrint.split(';');
if (this.config.campaignid != data[3]) {
this.date = today;
this.dayPrintCounter = 0;
this.totalPrintCounter = 0;
} else {
if (today != data[0]) {
this.date = today;
this.dayPrintCounter = 0;
} else {
this.date = data[0];
this.dayPrintCounter = parseInt(data[1]);
}
this.totalPrintCounter = parseInt(data[2]);
}
} else {
this.date = this.getTodayDate();
this.dayPrintCounter = 0;
this.totalPrintCounter = 0;
}
if ((this.totalPrintCounter >= limit.total && limit.total >= 0) || (this.dayPrintCounter >= limit.day && limit.day >= 0)) {
this.onLimitReached();
} else {
this.onLimitReset();
}
},
saveLastPrint: function() {
localStorage.setItem('lastPrint', this.date+";"+this.dayPrintCounter+";"+this.totalPrintCounter+";"+this.config.campaignid);
},
mayBeEraseLastPrint: function() {
var url = new URL(location.href);
if (url.searchParams.get('reset') !== null) {
localStorage.removeItem('lastPrint');
}
},
getTodayDate: function() {
return new Date().toISOString().substring(0, 10);
},
/**
* @private
* @param {String} url is the URL or name (absolute or relative) containing the button definitions
*/
fetchConfiguration: function(url) {
var data = null;
var xhr = new XMLHttpRequest();
var thiz = this;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4 && this.status == 200) {
try {
var config = JSON.parse(this.responseText);
thiz.setConfiguration(config);
} catch(e) {
alert(e.message);
}
}
});
xhr.open("GET", url);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.send(data);
},
/**
* @typedef {Object} ButtonSpec
* @summary Contains the buttons parameters.
* @property {String} url is the URL (relative or absolute) of the image to print.
* @property {String} [class] is the CSS class of the button.
* @property {Number} [left] is the left position of the button (can be omitted if given in the class).
* @property {Number} [top] is the top position of the button (can be omitted if given in the class).
* @property {Number} [width] is the button width (can be omitted if given in the class).
* @property {Number} [height] is the button height (can be omitted if given in the class).
*/
setConfiguration: function(config) {
this.config = config;
// Time between print
if (typeof config.printtimeout == "number") {
this.afterPrintTimeout = config.printtimeout;
}
// Set opening time...
try {
var opening = this.config.openingtime.split(":");
this.openingminutes = parseInt(opening[0]) * 60 + parseInt(opening[1]);
} catch(e) {
this.openingminutes = 0;
}
// Set closing time
try {
var closing = this.config.closingtime.split(":");
this.closingminutes = parseInt(closing[0]) * 60 + parseInt(closing[1]);
} catch(e) {
this.closingminutes = 24 * 60;
}
this.createButtons(config.buttons);
this.loadLastPrint();
// Initialize screen saver
this.screensaver = new ScreenSaver(config.screensaver.timeout, this.onSetScreenSaver.bind(this));
this.body.addEventListener("click", this.screensaver.onUserEvent.bind(this.screensaver));
this.body.addEventListener("touchstart", this.screensaver.onUserEvent.bind(this.screensaver));
this.container.addEventListener("transitionend", this.onScreenSaverOpacityTransition.bind(this));
this.onMinuteTick();
},
/**
* Callback invoked when the screensaver needs to be set visible or not.
* @private
* @param {boolean} display
*/
onSetScreenSaver: function(display) {
if (this.config.screensaver.enable) {
if (display) {
this.player.playFolder(this.config.screensaver.folder);
this.container.classList.add("screensaver");
} else {
this.disableClickFor(250); // Avoid a click on a button that may have been touched to disable the screensaver
this.container.classList.remove("screensaver", "no-touch");
this.player.stop();
}
}
},
/**
* Disable the click on buttons for a certain duration.
* @param {number} timeout number of milliseconds to wait before enabling the click again
*/
disableClickFor: function(timeout) {
this.clickDisabled = true;
window.setTimeout(function() {
this.clickDisabled = false;
}.bind(this), timeout)
},
/**
* Callback called when the opacity transition on the button container is over.
* It's time to disable the container so that the (hidden) buttons cannot be
* activated.
* @param {TransitionEvent} event
*/
onScreenSaverOpacityTransition: function(event) {
if (event.target == this.container) {
if (this.screensaver.isDisplayed()) {
this.container.classList.add("no-touch");
}
}
},
/**
* @private
* @param {ButtonSpec[]} config is an array of ButtonSpec
*/
createButtons: function(buttons) {
for (var i = 0 ; i < buttons.length ; i++) {
var button = buttons[i];
var div = document.createElement("div");
if (button.class !== undefined) {
div.className = button.class;
}
if (button.left !== undefined) {
div.style.left = button.left + "px";
}
if (button.top !== undefined) {
div.style.top = button.top + "px";
}
if (button.width !== undefined) {
div.style.width = button.width + "px";
}
if (button.height !== undefined) {
div.style.height = button.height + "px";
}
if (button.text !== undefined) {
div.innerText = button.text;
}
div.addEventListener("click", this.getClickDelegate(button, div));
div.addEventListener("animationend", this.getAnimationEndDelegate(div));
this.container.appendChild(div);
}
},
/**
* Set the printer object
* @param {Printer} printer
*/
setControlInterface: function(iface) {
this.printer = iface.printer;
this.logger = iface.logger;
this.player = iface.player;
// Register for printer events
this.printer.addListener(this.onPrinterEvent.bind(this));
// Get the printer state to enable printing...
this.printer.getState()
.then(function(state) {
this.setPrintAllowed(state.connected && state.online);
}.bind(this))
.catch(function() {});
// Handle contact input in the browser side
var config = {
controller: "browser",
lifetime: "url"
};
iface.contact.setInputConfiguration(config)
.then(function(e) {
console.log("Contact.setInputConfiguration(" + JSON.stringify(config) + ") => " + JSON.stringify(e));
})
.catch(function(e) {
console.error("Error: Contact.setInputConfiguration(" + JSON.stringify(config) + ") => " + JSON.stringify(e));
});
// Get contact input events
iface.contact.addListener(function(e) {
this.onInputContactEvent(e);
}.bind(this));
},
/**
* @private
* @param {Boolean} allow Is true to allow printing documents.
* @param {Number} [timeout] The number of milliseconds before executing the action
*/
setPrintAllowed: function(allow, timeout) {
var callback = function() {
if (allow) {
this.container.classList.remove("disabled");
} else {
this.container.classList.add("disabled");
}
this.printAllow = allow;
}.bind(this);
window.setTimeout(callback, timeout ? timeout : 0);
},
/**
* Convenience method: get an image URL from the button definition
* @private
* @param {String} url is an URL or a path relative to the current page.
*/
getUrl: function(url) {
if (url.startsWith("http://" || url.startsWith("https://"))) {
return url;
}
return document.URL.substr(0, document.URL.lastIndexOf('/')) + "/" + url;
},
/**
*
* @param {HTMLElement} div
* @returns a closure
*/
getAnimationEndDelegate: function(div) {
return function() {
div.classList.remove("animate")
};
},
/**
* Convenience method: get a function to execute on a click on a button area.
* @private
* @param {Object} button is the button definition
* @param {HTMLElement} div the div element for that button
*/
getClickDelegate: function(button, div) {
return function() {
this.onButtonClick(button, div);
}.bind(this);
},
/**
* Callback invoked when the user clicks on an area
* @private
* @param {Object} button is the button definition
* @param {HTMLElement} div the div element for that button
*/
onButtonClick: function(button, div) {
if (this.clickDisabled) {
return;
}
var printed = this.onPrint(button.url, button.log);
if (printed && !div.classList.contains('animate')) {
div.classList.add('animate');
}
},
onPrint: function(url, log) {
var limit = this.config.printlimit;
if (this.printAllow && this.printer) {
if ((this.dayPrintCounter < limit.day || limit.day < 0) && (this.totalPrintCounter < limit.total || limit.total < 0)) {
this.dayPrintCounter += 1;
this.totalPrintCounter += 1;
this.saveLastPrint();
var url = this.getUrl(url);
this.logButtonClick(log);
this.setPrintAllowed(false);
this.printer
.print({ url: url })
.then(this.onPrintStart.bind(this))
.catch(this.onPrintError.bind(this));
if ((this.dayPrintCounter >= limit.day && limit.day >= 0) || (this.totalPrintCounter >= limit.total && limit.total >= 0)) {
this.onLimitReached();
}
return true;
}
}
return false;
},
onInputContactEvent: function(e) {
var name = e.detail.name;
var contact = this.config.contacts[name];
if (contact) {
for (var i = 0 ; i < e.detail.values.length ; i++) {
var current = contact[i];
var value = e.detail.values[i];
if (current) {
if (!!current.state !== value && value == true) {
if (this.isOpen) {
this.onPrint(current.url, current.log);
}
}
current.state = value;
}
}
}
},
logButtonClick: function(log) {
this.log(log ? log : "button clicked");
},
/**
* Generic function to log a message
*/
log: function(message) {
if (this.logger != null) {
this.logger.log(this.config.logfile, this.getTimestamp() + " " + message);
}
},
getTimestamp: function() {
var now = new Date();
var twoDigit = function(n) {
return ("0" + n).slice(-2)
}
return now.getFullYear() + "-" + twoDigit(now.getMonth() + 1) + "-" + twoDigit(now.getDate()) + " " +
twoDigit(now.getHours()) + ":" + twoDigit(now.getMinutes()) + ":" + twoDigit(now.getSeconds());
},
/**
* Callback invoked on any print error.
* @private
*/
onPrintError: function() {
// You can display error message here...
this.log("Print failure");
this.setPrintAllowed(true, this.afterPrintTimeout);
},
/**
* Callback invoked when a printing has been done.
* Does not mean the printing is done, can be done, will be done.
* Does only gives the job identifier...
* @param {Number} id is the job identifier
*/
onPrintStart: function(id) {
// Print has started, watch printer events...
this.jobid = id;
},
/**
* Callback invoked when a printer related event is received.
* @param {PrinterStateEvent|JobStateEvent} event is the event
*/
onPrinterEvent: function(event) {
var detail = event.detail;
switch (detail.type) {
case 'job-state':
this.onJobStateEvent(detail.job);
break;
case 'printer-state':
this.onPrinterStateEvent(detail.state);
break;
default:
break;
}
},
/**
* Callback invoked when a print job event is received.
* @param {JobState} job is the job that has changed.
*/
onJobStateEvent: function(job) {
// Only watch the last printed job (our job)...
if (job.id == this.jobid) {
switch(job.state) {
case 'failed':
// Sorry for the convenience...
this.onPrintError();
break;
case 'printed':
// The document has been successfully printer, say thank you...
this.setPrintAllowed(true, this.afterPrintTimeout);
break;
case 'finished':
// Can print a new one... or wait a few seconds...
break;
}
}
},
/**
* Callback invoked when a printer event is received.
* It tells whether the printer is online, the paper is available...
* @param {PrinterState} state is the printer state
*/
onPrinterStateEvent: function(state) {
if (state.online) {
// Documents can be printed...
this.setPrintAllowed(true);
} else {
// Display other contents or at least don't allow printing
this.setPrintAllowed(false);
}
},
/**
* This method is called every minute and is responsible for calling
* the onOpeningTime() / onClosingTime() methods.
*/
onMinuteTick: function() {
var open = this.isOpenNow();
if (this.isOpen !== open) {
this.isOpen = open;
if (open) {
this.onOpeningTime();
var today = this.getTodayDate();
if (today != this.date) {
this.dayPrintCounter = 0;
this.date = today;
var limitTotal = this.config.printlimit.total;
if (this.totalPrintCounter < limitTotal || limitTotal < 0) {
this.onLimitReset();
}
}
} else {
this.onClosingTime();
}
}
this.setTimeoutTick();
},
/**
* Set a timeout to execute the the opening / close verification every minute.
* Quite expansive but more reliable when setting the time.
*/
setTimeoutTick: function() {
var now = new Date();
var nextms = 1000 * (61 - (now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds()) % 60);
window.setTimeout(this.onMinuteTick.bind(this), nextms);
},
/**
* Check whether the app in the opening/closing intervale.
* @return {Boolean} true if the app is open
*/
isOpenNow: function() {
var now = new Date();
// Number of minutes since midnight
var nowminutes = now.getHours() * 60 + now.getMinutes();
if ((nowminutes < this.openingminutes) || (nowminutes >= this.closingminutes))
return false;
return true;
},
onOpeningTime: function() {
// Do whatever you want to do on opening time (show buttons...)
this.container.classList.remove("store-closed");
this.screensaver.setEnabled(true);
},
onClosingTime: function() {
// Do whatever you want to do on closing time (hide buttons, display something else...)
this.container.classList.add("store-closed");
this.screensaver.setEnabled(false);
},
onLimitReached: function() {
// Do whatever you want when the print limit has been reached (hide buttons, display something else...)
this.container.classList.add('limit-reached');
},
onLimitReset: function() {
// Do whatever you want when the print limit has been reset (show the buttons...) and
// is is now possible to print.
this.container.classList.remove('limit-reached');
}
};
/**
* Screen saver manager
* @param {Number} duration is the duration to wait before starting the screensaver
* @param {function(boolean)} onDisplay is the callback invoked when the screensaver
* has to be displayed or hidden.
*/
function ScreenSaver(duration, onDisplay) {
this.enabled = false;
this.timeout = null;
this.duration = duration * 1000;
this.displayed = undefined; // Boolean, undefined to trigger a first onDisplay() when calling setEnabled() for the first time
this.onDisplay = onDisplay;
this._onTimeoutBind = this._onTimeout.bind(this);
}
ScreenSaver.prototype = {
setEnabled: function(enabled) {
if (this.enabled !== !!enabled) {
this.enabled = !!enabled;
}
if (this.enabled) {
this._startTimeout();
} else {
this._clearTimeout();
}
this._setDisplay(this.enabled && this.displayed);
},
onUserEvent: function() {
this._setDisplay(false);
this._startTimeout();
},
isDisplayed: function() {
return this.displayed && this.enabled;
},
_setDisplay: function(displayed) {
var value = !!displayed;
if (this.displayed !== value) {
this.displayed = value;
this.onDisplay(value);
}
},
_startTimeout: function() {
this._clearTimeout(); // Paranoid
if (this.enabled && this.duration >= 1000) {
this.timeout = window.setTimeout(this._onTimeoutBind, this.duration);
}
},
_onTimeout: function() {
this.displayed = true;
this.onDisplay(true);
},
_clearTimeout: function() {
if (this.timeout != null) {
window.clearTimeout(this.timeout);
this.timeout = null;
}
}
}
But I don't know what I need to change or what can I simplify