gecko-dev/toolkit/devtools/qrcode/index.js

117 lines
3.5 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Cu } = require("chrome");
const { Promise: promise } =
Cu.import("resource://gre/modules/Promise.jsm", {});
// Lazily require encoder and decoder in case only one is needed
Object.defineProperty(this, "Encoder", {
get: () => require("./encoder/index").Encoder
});
Object.defineProperty(this, "QRRSBlock", {
get: () => require("./encoder/index").QRRSBlock
});
Object.defineProperty(this, "QRErrorCorrectLevel", {
get: () => require("./encoder/index").QRErrorCorrectLevel
});
Object.defineProperty(this, "decoder", {
get: () => {
// Some applications don't ship the decoder, see moz.build
try {
return require("./decoder/index");
} catch(e) {
return null;
}
}
});
/**
* There are many "versions" of QR codes, which describes how many dots appear
* in the resulting image, thus limiting the amount of data that can be
* represented.
*
* The encoder used here allows for versions 1 - 10 (more dots for larger
* versions).
*
* It expects you to pick a version large enough to contain your message. Here
* we search for the mimimum version based on the message length.
* @param string message
* Text to encode
* @param string quality
* Quality level: L, M, Q, H
* @return integer
*/
exports.findMinimumVersion = function(message, quality) {
let msgLength = message.length;
let qualityLevel = QRErrorCorrectLevel[quality];
for (let version = 1; version <= 10; version++) {
let rsBlocks = QRRSBlock.getRSBlocks(version, qualityLevel);
let maxLength = rsBlocks.reduce((prev, block) => {
return prev + block.dataCount;
}, 0);
// Remove two bytes to fit header info
maxLength -= 2;
if (msgLength <= maxLength) {
return version;
}
}
throw new Error("Message too large");
};
/**
* Simple wrapper around the underlying encoder's API.
* @param string message
* Text to encode
* @param string quality (optional)
Quality level: L, M, Q, H
* @param integer version (optional)
* QR code "version" large enough to contain the message
* @return object with the following fields:
* * src: an image encoded a data URI
* * height: image height
* * width: image width
*/
exports.encodeToDataURI = function(message, quality, version) {
quality = quality || "H";
version = version || exports.findMinimumVersion(message, quality);
let encoder = new Encoder(version, quality);
encoder.addData(message);
encoder.make();
return encoder.createImgData();
};
/**
* Simple wrapper around the underlying decoder's API.
* @param string URI
* URI of an image of a QR code
* @return Promise
* The promise will be resolved with a string, which is the data inside
* the QR code.
*/
exports.decodeFromURI = function(URI) {
if (!decoder) {
return promise.reject();
}
let deferred = promise.defer();
decoder.decodeFromURI(URI, deferred.resolve, deferred.reject);
return deferred.promise;
};
/**
* Decode a QR code that has been drawn to a canvas element.
* @param Canvas canvas
* <canvas> element to read from
* @return string
* The data inside the QR code
*/
exports.decodeFromCanvas = function(canvas) {
if (!decoder) {
throw new Error("Decoder not available");
}
return decoder.decodeFromCanvas(canvas);
};