diff --git a/js/qz-tray.js b/js/qz-tray.js
index 354a7c9a6..8f71f6104 100644
--- a/js/qz-tray.js
+++ b/js/qz-tray.js
@@ -669,7 +669,7 @@ var qz = (function() {
if (data[i].constructor === Object) {
var absolute = false;
- if (data[i].data && data[i].data.search(/data:image\/\w+;base64,/) === 0) {
+ if (data[i].data && data[i].data.search && data[i].data.search(/data:image\/\w+;base64,/) === 0) {
//upgrade from old base64 behavior
data[i].flavor = "base64";
data[i].data = data[i].data.replace(/^data:image\/\w+;base64,/, "");
@@ -767,12 +767,67 @@ var qz = (function() {
}
// Promise won't reject on throw; yet better than 'undefined'
throw new Error("A connection to QZ has not been established yet");
- }
+ },
+
+ uint8ArrayToHex: function(uint8) {
+ return Array.from(uint8)
+ .map(function(i) { return i.toString(16).padStart(2, '0'); })
+ .join('');
+ },
+
+ uint8ArrayToBase64: function(uint8) {
+ /**
+ * Adapted from Egor Nepomnyaschih's code under MIT Licence (C) 2020
+ * see https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727
+ */
+ var map = [
+ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
+ "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
+ "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"
+ ];
+
+ var result = '', i, l = uint8.length;
+ for (i = 2; i < l; i += 3) {
+ result += map[uint8[i - 2] >> 2];
+ result += map[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];
+ result += map[((uint8[i - 1] & 0x0F) << 2) | (uint8[i] >> 6)];
+ result += map[uint8[i] & 0x3F];
+ }
+ if (i === l + 1) { // 1 octet yet to write
+ result += map[uint8[i - 2] >> 2];
+ result += map[(uint8[i - 2] & 0x03) << 4];
+ result += "==";
+ }
+ if (i === l) { // 2 octets yet to write
+ result += map[uint8[i - 2] >> 2];
+ result += map[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];
+ result += map[(uint8[i - 1] & 0x0F) << 2];
+ result += "=";
+ }
+ return result;
+ },
},
compatible: {
/** Converts message format to a previous version's */
data: function(printData) {
+ // special handling for Uint8Array
+ if (printData.constructor === Object && printData.data instanceof Uint8Array) {
+ if (printData.flavor) {
+ var flavor = printData.flavor.toString().toUpperCase();
+ switch(flavor) {
+ case 'BASE64':
+ printData.data = _qz.tools.uint8ArrayToBase64(printData.data);
+ break;
+ case 'HEX':
+ printData.data = _qz.tools.uint8ArrayToHex(printData.data);
+ break;
+ default:
+ throw new Error("Uint8Array conversion to '" + flavor + "' is not supported.");
+ }
+ }
+ }
+
if (_qz.tools.isVersion(2, 0)) {
/*
2.0.x conversion
diff --git a/js/sample/array-from-pollyfill.js b/js/sample/array-from-pollyfill.js
new file mode 100644
index 000000000..3cf8d5454
--- /dev/null
+++ b/js/sample/array-from-pollyfill.js
@@ -0,0 +1,76 @@
+if (!Array.from) {
+ Array.from = (function () {
+ var toStr = Object.prototype.toString;
+ var isCallable = function (fn) {
+ return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
+ };
+ var toInteger = function (value) {
+ var number = Number(value);
+ if (isNaN(number)) { return 0; }
+ if (number === 0 || !isFinite(number)) { return number; }
+ return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
+ };
+ var maxSafeInteger = Math.pow(2, 53) - 1;
+ var toLength = function (value) {
+ var len = toInteger(value);
+ return Math.min(Math.max(len, 0), maxSafeInteger);
+ };
+
+ // The length property of the from method is 1.
+ return function from(arrayLike/*, mapFn, thisArg */) {
+ // 1. Let C be the this value.
+ var C = this;
+
+ // 2. Let items be ToObject(arrayLike).
+ var items = Object(arrayLike);
+
+ // 3. ReturnIfAbrupt(items).
+ if (arrayLike == null) {
+ throw new TypeError("Array.from requires an array-like object - not null or undefined");
+ }
+
+ // 4. If mapfn is undefined, then let mapping be false.
+ var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
+ var T;
+ if (typeof mapFn !== 'undefined') {
+ // 5. else
+ // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
+ if (!isCallable(mapFn)) {
+ throw new TypeError('Array.from: when provided, the second argument must be a function');
+ }
+
+ // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
+ if (arguments.length > 2) {
+ T = arguments[2];
+ }
+ }
+
+ // 10. Let lenValue be Get(items, "length").
+ // 11. Let len be ToLength(lenValue).
+ var len = toLength(items.length);
+
+ // 13. If IsConstructor(C) is true, then
+ // 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
+ // 14. a. Else, Let A be ArrayCreate(len).
+ var A = isCallable(C) ? Object(new C(len)) : new Array(len);
+
+ // 16. Let k be 0.
+ var k = 0;
+ // 17. Repeat, while k < len… (also steps a - h)
+ var kValue;
+ while (k < len) {
+ kValue = items[k];
+ if (mapFn) {
+ A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
+ } else {
+ A[k] = kValue;
+ }
+ k += 1;
+ }
+ // 18. Let putStatus be Put(A, "length", len, true).
+ A.length = len;
+ // 20. Return A.
+ return A;
+ };
+ }());
+}
\ No newline at end of file
diff --git a/js/sample/padstart-pollyfill.js b/js/sample/padstart-pollyfill.js
new file mode 100644
index 000000000..94625a641
--- /dev/null
+++ b/js/sample/padstart-pollyfill.js
@@ -0,0 +1,21 @@
+/**
+ * String.prototype.padStart() polyfill
+ * https://github.com/uxitten/polyfill/blob/master/string.polyfill.js
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
+ */
+if (!String.prototype.padStart) {
+ String.prototype.padStart = function padStart(targetLength,padString) {
+ targetLength = targetLength>>0; //truncate if number or convert non-number to 0;
+ padString = String((typeof padString !== 'undefined' ? padString : ' '));
+ if (this.length > targetLength) {
+ return String(this);
+ }
+ else {
+ targetLength = targetLength-this.length;
+ if (targetLength > padString.length) {
+ padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed
+ }
+ return padString.slice(0,targetLength) + String(this);
+ }
+ };
+}
diff --git a/sample.html b/sample.html
index 475b0fb3b..b8511cdf2 100755
--- a/sample.html
+++ b/sample.html
@@ -11,6 +11,8 @@
+
+