barcode.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. $(function() {
  2. var resultCollector = Quagga.ResultCollector.create({
  3. capture: true,
  4. capacity: 20,
  5. blacklist: [{
  6. code: "WIWV8ETQZ1", format: "code_93"
  7. }, {
  8. code: "EH3C-%GU23RK3", format: "code_93"
  9. }, {
  10. code: "O308SIHQOXN5SA/PJ", format: "code_93"
  11. }, {
  12. code: "DG7Q$TV8JQ/EN", format: "code_93"
  13. }, {
  14. code: "VOFD1DB5A.1F6QU", format: "code_93"
  15. }, {
  16. code: "4SO64P4X8 U4YUU1T-", format: "code_93"
  17. }],
  18. filter: function(codeResult) {
  19. // only store results which match this constraint
  20. // e.g.: codeResult
  21. return true;
  22. }
  23. });
  24. var App = {
  25. init: function() {
  26. var self = this;
  27. Quagga.init(this.state, function(err) {
  28. if (err) {
  29. return self.handleError(err);
  30. }
  31. //Quagga.registerResultCollector(resultCollector);
  32. App.attachListeners();
  33. App.checkCapabilities();
  34. Quagga.start();
  35. });
  36. },
  37. handleError: function(err) {
  38. console.log(err);
  39. },
  40. checkCapabilities: function() {
  41. var track = Quagga.CameraAccess.getActiveTrack();
  42. var capabilities = {};
  43. if (typeof track.getCapabilities === 'function') {
  44. capabilities = track.getCapabilities();
  45. }
  46. this.applySettingsVisibility('zoom', capabilities.zoom);
  47. this.applySettingsVisibility('torch', capabilities.torch);
  48. },
  49. updateOptionsForMediaRange: function(node, range) {
  50. console.log('updateOptionsForMediaRange', node, range);
  51. var NUM_STEPS = 6;
  52. var stepSize = (range.max - range.min) / NUM_STEPS;
  53. var option;
  54. var value;
  55. while (node.firstChild) {
  56. node.removeChild(node.firstChild);
  57. }
  58. for (var i = 0; i <= NUM_STEPS; i++) {
  59. value = range.min + (stepSize * i);
  60. option = document.createElement('option');
  61. option.value = value;
  62. option.innerHTML = value;
  63. node.appendChild(option);
  64. }
  65. },
  66. applySettingsVisibility: function(setting, capability) {
  67. // depending on type of capability
  68. if (typeof capability === 'boolean') {
  69. var node = document.querySelector('input[name="settings_' + setting + '"]');
  70. if (node) {
  71. node.parentNode.style.display = capability ? 'block' : 'none';
  72. }
  73. return;
  74. }
  75. if (window.MediaSettingsRange && capability instanceof window.MediaSettingsRange) {
  76. var node = document.querySelector('select[name="settings_' + setting + '"]');
  77. if (node) {
  78. this.updateOptionsForMediaRange(node, capability);
  79. node.parentNode.style.display = 'block';
  80. }
  81. return;
  82. }
  83. },
  84. initCameraSelection: function(){
  85. var streamLabel = Quagga.CameraAccess.getActiveStreamLabel();
  86. return Quagga.CameraAccess.enumerateVideoDevices()
  87. .then(function(devices) {
  88. function pruneText(text) {
  89. return text.length > 30 ? text.substr(0, 30) : text;
  90. }
  91. var $deviceSelection = document.getElementById("deviceSelection");
  92. while ($deviceSelection.firstChild) {
  93. $deviceSelection.removeChild($deviceSelection.firstChild);
  94. }
  95. devices.forEach(function(device) {
  96. var $option = document.createElement("option");
  97. $option.value = device.deviceId || device.id;
  98. $option.appendChild(document.createTextNode(pruneText(device.label || device.deviceId || device.id)));
  99. $option.selected = streamLabel === device.label;
  100. $deviceSelection.appendChild($option);
  101. });
  102. });
  103. },
  104. attachListeners: function() {
  105. var self = this;
  106. self.initCameraSelection();
  107. $(".controls").on("click", "button.stop", function(e) {
  108. e.preventDefault();
  109. Quagga.stop();
  110. self._printCollectedResults();
  111. });
  112. $(".controls .reader-config-group").on("change", "input, select", function(e) {
  113. e.preventDefault();
  114. var $target = $(e.target),
  115. value = $target.attr("type") === "checkbox" ? $target.prop("checked") : $target.val(),
  116. name = $target.attr("name"),
  117. state = self._convertNameToState(name);
  118. console.log("Value of "+ state + " changed to " + value);
  119. self.setState(state, value);
  120. });
  121. },
  122. _printCollectedResults: function() {
  123. var results = resultCollector.getResults(),
  124. $ul = $("#result_strip ul.collector");
  125. results.forEach(function(result) {
  126. var $li = $('<li><div class="thumbnail"><div class="imgWrapper"><img /></div><div class="caption"><h4 class="code"></h4></div></div></li>');
  127. $li.find("img").attr("src", result.frame);
  128. $li.find("h4.code").html(result.codeResult.code + " (" + result.codeResult.format + ")");
  129. $ul.prepend($li);
  130. });
  131. },
  132. _accessByPath: function(obj, path, val) {
  133. var parts = path.split('.'),
  134. depth = parts.length,
  135. setter = (typeof val !== "undefined") ? true : false;
  136. return parts.reduce(function(o, key, i) {
  137. if (setter && (i + 1) === depth) {
  138. if (typeof o[key] === "object" && typeof val === "object") {
  139. Object.assign(o[key], val);
  140. } else {
  141. o[key] = val;
  142. }
  143. }
  144. return key in o ? o[key] : {};
  145. }, obj);
  146. },
  147. _convertNameToState: function(name) {
  148. return name.replace("_", ".").split("-").reduce(function(result, value) {
  149. return result + value.charAt(0).toUpperCase() + value.substring(1);
  150. });
  151. },
  152. detachListeners: function() {
  153. $(".controls").off("click", "button.stop");
  154. $(".controls .reader-config-group").off("change", "input, select");
  155. },
  156. applySetting: function(setting, value) {
  157. var track = Quagga.CameraAccess.getActiveTrack();
  158. if (track && typeof track.getCapabilities === 'function') {
  159. switch (setting) {
  160. case 'zoom':
  161. return track.applyConstraints({advanced: [{zoom: parseFloat(value)}]});
  162. case 'torch':
  163. return track.applyConstraints({advanced: [{torch: !!value}]});
  164. }
  165. }
  166. },
  167. setState: function(path, value) {
  168. var self = this;
  169. if (typeof self._accessByPath(self.inputMapper, path) === "function") {
  170. value = self._accessByPath(self.inputMapper, path)(value);
  171. }
  172. if (path.startsWith('settings.')) {
  173. var setting = path.substring(9);
  174. return self.applySetting(setting, value);
  175. }
  176. self._accessByPath(self.state, path, value);
  177. console.log(JSON.stringify(self.state));
  178. App.detachListeners();
  179. Quagga.stop();
  180. App.init();
  181. },
  182. inputMapper: {
  183. inputStream: {
  184. constraints: function(value){
  185. if (/^(\d+)x(\d+)$/.test(value)) {
  186. var values = value.split('x');
  187. return {
  188. width: {min: parseInt(values[0])},
  189. height: {min: parseInt(values[1])}
  190. };
  191. }
  192. return {
  193. deviceId: value
  194. };
  195. }
  196. },
  197. numOfWorkers: function(value) {
  198. return parseInt(value);
  199. },
  200. decoder: {
  201. readers: function(value) {
  202. if (value === 'ean_extended') {
  203. return [{
  204. format: "ean_reader",
  205. config: {
  206. supplements: [
  207. 'ean_5_reader', 'ean_2_reader'
  208. ]
  209. }
  210. }];
  211. }
  212. return [{
  213. format: value + "_reader",
  214. config: {}
  215. }];
  216. }
  217. }
  218. },
  219. state: {
  220. inputStream: {
  221. type : "LiveStream",
  222. constraints: {
  223. width: {min: 640},
  224. height: {min: 480},
  225. facingMode: "environment",
  226. aspectRatio: {min: 1, max: 2}
  227. }
  228. },
  229. locator: {
  230. patchSize: "medium",
  231. halfSample: true
  232. },
  233. numOfWorkers: 2,
  234. frequency: 10,
  235. decoder: {
  236. readers : [{
  237. format: "code_128_reader",
  238. config: {}
  239. }]
  240. },
  241. locate: true
  242. },
  243. lastResult : null
  244. };
  245. App.init();
  246. Quagga.onProcessed(function(result) {
  247. var drawingCtx = Quagga.canvas.ctx.overlay,
  248. drawingCanvas = Quagga.canvas.dom.overlay;
  249. if (result) {
  250. if (result.boxes) {
  251. drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
  252. result.boxes.filter(function (box) {
  253. return box !== result.box;
  254. }).forEach(function (box) {
  255. Quagga.ImageDebug.drawPath(box, {x: 0, y: 1}, drawingCtx, {color: "green", lineWidth: 2});
  256. });
  257. }
  258. if (result.box) {
  259. Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, drawingCtx, {color: "#00F", lineWidth: 2});
  260. }
  261. if (result.codeResult && result.codeResult.code) {
  262. Quagga.ImageDebug.drawPath(result.line, {x: 'x', y: 'y'}, drawingCtx, {color: 'red', lineWidth: 3});
  263. }
  264. }
  265. });
  266. Quagga.onDetected(function(result) {
  267. var code = result.codeResult.code;
  268. if (App.lastResult !== code) {
  269. App.lastResult = code;
  270. var $node = null, canvas = Quagga.canvas.dom.image;
  271. $node = $('<li><div class="thumbnail"><div class="imgWrapper"><img /></div><div class="caption"><h4 class="code"></h4></div></div></li>');
  272. $node.find("img").attr("src", canvas.toDataURL());
  273. $node.find("h4.code").html(code);
  274. $("#result_strip ul.thumbnails").prepend($node);
  275. }
  276. });
  277. });