index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. const { Cu } = require("chrome");
  6. const promise = require("promise");
  7. const defer = require("devtools/shared/defer");
  8. // Lazily require encoder and decoder in case only one is needed
  9. Object.defineProperty(this, "Encoder", {
  10. get: () => require("./encoder/index").Encoder
  11. });
  12. Object.defineProperty(this, "QRRSBlock", {
  13. get: () => require("./encoder/index").QRRSBlock
  14. });
  15. Object.defineProperty(this, "QRErrorCorrectLevel", {
  16. get: () => require("./encoder/index").QRErrorCorrectLevel
  17. });
  18. Object.defineProperty(this, "decoder", {
  19. get: () => {
  20. // Some applications don't ship the decoder, see moz.build
  21. try {
  22. return require("./decoder/index");
  23. } catch (e) {
  24. return null;
  25. }
  26. }
  27. });
  28. /**
  29. * There are many "versions" of QR codes, which describes how many dots appear
  30. * in the resulting image, thus limiting the amount of data that can be
  31. * represented.
  32. *
  33. * The encoder used here allows for versions 1 - 10 (more dots for larger
  34. * versions).
  35. *
  36. * It expects you to pick a version large enough to contain your message. Here
  37. * we search for the mimimum version based on the message length.
  38. * @param string message
  39. * Text to encode
  40. * @param string quality
  41. * Quality level: L, M, Q, H
  42. * @return integer
  43. */
  44. exports.findMinimumVersion = function (message, quality) {
  45. let msgLength = message.length;
  46. let qualityLevel = QRErrorCorrectLevel[quality];
  47. for (let version = 1; version <= 10; version++) {
  48. let rsBlocks = QRRSBlock.getRSBlocks(version, qualityLevel);
  49. let maxLength = rsBlocks.reduce((prev, block) => {
  50. return prev + block.dataCount;
  51. }, 0);
  52. // Remove two bytes to fit header info
  53. maxLength -= 2;
  54. if (msgLength <= maxLength) {
  55. return version;
  56. }
  57. }
  58. throw new Error("Message too large");
  59. };
  60. /**
  61. * Simple wrapper around the underlying encoder's API.
  62. * @param string message
  63. * Text to encode
  64. * @param string quality (optional)
  65. Quality level: L, M, Q, H
  66. * @param integer version (optional)
  67. * QR code "version" large enough to contain the message
  68. * @return object with the following fields:
  69. * * src: an image encoded a data URI
  70. * * height: image height
  71. * * width: image width
  72. */
  73. exports.encodeToDataURI = function (message, quality, version) {
  74. quality = quality || "H";
  75. version = version || exports.findMinimumVersion(message, quality);
  76. let encoder = new Encoder(version, quality);
  77. encoder.addData(message);
  78. encoder.make();
  79. return encoder.createImgData();
  80. };
  81. /**
  82. * Simple wrapper around the underlying decoder's API.
  83. * @param string URI
  84. * URI of an image of a QR code
  85. * @return Promise
  86. * The promise will be resolved with a string, which is the data inside
  87. * the QR code.
  88. */
  89. exports.decodeFromURI = function (URI) {
  90. if (!decoder) {
  91. return promise.reject();
  92. }
  93. let deferred = defer();
  94. decoder.decodeFromURI(URI, deferred.resolve, deferred.reject);
  95. return deferred.promise;
  96. };
  97. /**
  98. * Decode a QR code that has been drawn to a canvas element.
  99. * @param Canvas canvas
  100. * <canvas> element to read from
  101. * @return string
  102. * The data inside the QR code
  103. */
  104. exports.decodeFromCanvas = function (canvas) {
  105. if (!decoder) {
  106. throw new Error("Decoder not available");
  107. }
  108. return decoder.decodeFromCanvas(canvas);
  109. };