diff --git a/README.md b/README.md index 4eec5cb..e1f7a8c 100644 --- a/README.md +++ b/README.md @@ -107,18 +107,26 @@ docker build -t maslick/emscripten-zbar-sdk -f docker/Dockerfile docker ### Build WASM artifacts ```shell -# React app +# Linux, Mac Intel docker run \ -e INPUT_FILE=zbar/qr.cpp \ -e OUTPUT_FILE=zbar \ -e OUTPUT_DIR=public/wasm \ -v $(pwd):/app \ maslick/emscripten-zbar-sdk make -B + +# Mac M1/M2 +docker run \ + --platform linux/amd64 \ + -e INPUT_FILE=zbar/qr.cpp \ + -e OUTPUT_FILE=zbar \ + -e OUTPUT_DIR=public/wasm \ + -v $(pwd):/app \ + maslick/emscripten-zbar-sdk make -B ``` ### Clean the build artifacts (if necessary): ```shell -# React app OUTPUT_DIR=public/wasm OUTPUT_FILE=zbar make clean ``` diff --git a/package.json b/package.json index fcfe3d1..d7dd96e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "koder-react", - "version": "1.10.0", + "version": "1.11.0", "homepage": "./", "private": true, "description": "QR/bar code scanner for the Browser", diff --git a/public/wasm/koder.js b/public/wasm/koder.js index a359eec..4f8e668 100644 --- a/public/wasm/koder.js +++ b/public/wasm/koder.js @@ -2,7 +2,6 @@ class Koder { initialize(config) { return (async () => { // Load WASM file - console.log("Browser"); config ||= {}; const directory = config.wasmDirectory || "./wasm"; this.mod = await CreateKoder({locateFile: file => `${directory}/${file}`}); @@ -12,7 +11,8 @@ class Koder { createBuffer: this.mod.cwrap('createBuffer', 'number', ['number']), deleteBuffer: this.mod.cwrap('deleteBuffer', '', ['number']), triggerDecode: this.mod.cwrap('triggerDecode', 'number', ['number', 'number', 'number']), - getScanResults: this.mod.cwrap('getScanResults', 'number', []) + getScanResults: this.mod.cwrap('getScanResults', 'number', []), + getResultType: this.mod.cwrap('getResultType', 'number', []), }; // return the class @@ -26,7 +26,11 @@ class Koder { const results = []; if (this.api.triggerDecode(buffer, width, height) > 0) { const resultAddress = this.api.getScanResults(); - results.push(this.mod.UTF8ToString(resultAddress)); + const resultType = this.api.getResultType(); + results.push({ + code: this.mod.UTF8ToString(resultAddress), + type: this.mod.UTF8ToString(resultType) + }); this.api.deleteBuffer(resultAddress); } if (results.length > 0) return results[0]; diff --git a/public/wasm/zbar.js b/public/wasm/zbar.js index 0311179..317f975 100644 --- a/public/wasm/zbar.js +++ b/public/wasm/zbar.js @@ -33,11 +33,11 @@ c)?g(Math.ceil((31-q.getDate()+(La(V(c.getFullYear())?W:X,c.getMonth()-1)-31)+c. var Pa={k:function(a,b,e,f){J("Assertion failed: "+P(a)+", at: "+[b?P(b):"unknown filename",e,f?P(f):"unknown function"])},a:function(){J("")},j:function(a,b){if(0===a)a=Date.now();else if(1===a||4===a)a=Da();else return Q[Oa()>>2]=28,-1;Q[b>>2]=a/1E3|0;Q[b+4>>2]=a%1E3*1E6|0;return 0},c:function(a){var b=N.length;a>>>=0;if(2147483648=e;e*=2){var f=b*(1+.2/e);f=Math.min(f,a+100663296);f=Math.max(a,f);0>>16);ra();var h=1;break a}catch(g){}h=void 0}if(h)return!0}return!1},e:function(a,b){var e=0;Ha().forEach(function(f,h){var g=b+e;h=Q[a+4*h>>2]=g;for(g=0;g>0]=f.charCodeAt(g);O[h>>0]=0;e+=f.length+1});return 0},f:function(a,b){var e=Ha();Q[a>>2]=e.length;var f=0;e.forEach(function(h){f+=h.length+1});Q[b>>2]=f;return 0},h:function(){return 0},g:function(a,b,e,f){a=Ka.O(a);b=Ka.M(a,b,e);Q[f>>2]=b;return 0},i:function(){},b:function(a,b,e,f){for(var h=0,g=0;g>2],r=Q[b+4>>2];b+=8;for(var t=0;t>2]=h;return 0},d:function(a,b,e,f){return Ma(a,b,e,f)}}; -(function(){function a(h){d.asm=h.exports;K=d.asm.l;ra();sa=d.asm.s;ua.unshift(d.asm.m);R--;d.monitorRunDependencies&&d.monitorRunDependencies(R);0==R&&(null!==ya&&(clearInterval(ya),ya=null),S&&(h=S,S=null,h()))}function b(h){a(h.instance)}function e(h){return Ca().then(function(g){return WebAssembly.instantiate(g,f)}).then(function(g){return g}).then(h,function(g){H("failed to asynchronously prepare wasm: "+g);J(g)})}var f={a:Pa};R++;d.monitorRunDependencies&&d.monitorRunDependencies(R);if(d.instantiateWasm)try{return d.instantiateWasm(f, +(function(){function a(h){d.asm=h.exports;K=d.asm.l;ra();sa=d.asm.t;ua.unshift(d.asm.m);R--;d.monitorRunDependencies&&d.monitorRunDependencies(R);0==R&&(null!==ya&&(clearInterval(ya),ya=null),S&&(h=S,S=null,h()))}function b(h){a(h.instance)}function e(h){return Ca().then(function(g){return WebAssembly.instantiate(g,f)}).then(function(g){return g}).then(h,function(g){H("failed to asynchronously prepare wasm: "+g);J(g)})}var f={a:Pa};R++;d.monitorRunDependencies&&d.monitorRunDependencies(R);if(d.instantiateWasm)try{return d.instantiateWasm(f, a)}catch(h){return H("Module.instantiateWasm callback failed with error: "+h),!1}(function(){return I||"function"!==typeof WebAssembly.instantiateStreaming||za()||T.startsWith("file://")||"function"!==typeof fetch?e(b):fetch(T,{credentials:"same-origin"}).then(function(h){return WebAssembly.instantiateStreaming(h,f).then(b,function(g){H("wasm streaming compile failed: "+g);H("falling back to ArrayBuffer instantiation");return e(b)})})})().catch(n);return{}})(); -d.___wasm_call_ctors=function(){return(d.___wasm_call_ctors=d.asm.m).apply(null,arguments)};d._createBuffer=function(){return(d._createBuffer=d.asm.n).apply(null,arguments)};d._deleteBuffer=function(){return(d._deleteBuffer=d.asm.o).apply(null,arguments)};d._triggerDecode=function(){return(d._triggerDecode=d.asm.p).apply(null,arguments)};d._getScanResults=function(){return(d._getScanResults=d.asm.q).apply(null,arguments)};d._main=function(){return(d._main=d.asm.r).apply(null,arguments)}; -var Oa=d.___errno_location=function(){return(Oa=d.___errno_location=d.asm.t).apply(null,arguments)},ka=d.stackSave=function(){return(ka=d.stackSave=d.asm.u).apply(null,arguments)},la=d.stackRestore=function(){return(la=d.stackRestore=d.asm.v).apply(null,arguments)},M=d.stackAlloc=function(){return(M=d.stackAlloc=d.asm.w).apply(null,arguments)};d.cwrap=function(a,b,e,f){e=e||[];var h=e.every(function(g){return"number"===g});return"string"!==b&&h&&!f?d["_"+a]:function(){return ia(a,b,e,arguments)}}; -d.UTF8ToString=P;var Z;function G(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}S=function Qa(){Z||Ra();Z||(S=Qa)}; +d.___wasm_call_ctors=function(){return(d.___wasm_call_ctors=d.asm.m).apply(null,arguments)};d._createBuffer=function(){return(d._createBuffer=d.asm.n).apply(null,arguments)};d._deleteBuffer=function(){return(d._deleteBuffer=d.asm.o).apply(null,arguments)};d._triggerDecode=function(){return(d._triggerDecode=d.asm.p).apply(null,arguments)};d._getScanResults=function(){return(d._getScanResults=d.asm.q).apply(null,arguments)};d._getResultType=function(){return(d._getResultType=d.asm.r).apply(null,arguments)}; +d._main=function(){return(d._main=d.asm.s).apply(null,arguments)};var Oa=d.___errno_location=function(){return(Oa=d.___errno_location=d.asm.u).apply(null,arguments)},ka=d.stackSave=function(){return(ka=d.stackSave=d.asm.v).apply(null,arguments)},la=d.stackRestore=function(){return(la=d.stackRestore=d.asm.w).apply(null,arguments)},M=d.stackAlloc=function(){return(M=d.stackAlloc=d.asm.x).apply(null,arguments)}; +d.cwrap=function(a,b,e,f){e=e||[];var h=e.every(function(g){return"number"===g});return"string"!==b&&h&&!f?d["_"+a]:function(){return ia(a,b,e,arguments)}};d.UTF8ToString=P;var Z;function G(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}S=function Qa(){Z||Ra();Z||(S=Qa)}; function Ra(a){function b(){if(!Z&&(Z=!0,d.calledRun=!0,!L)){U(ua);U(va);ba(d);if(d.onRuntimeInitialized)d.onRuntimeInitialized();if(Sa){var e=a,f=d._main;e=e||[];var h=e.length+1,g=M(4*(h+1));Q[g>>2]=pa(v);for(var m=1;m>2)+m]=pa(e[m-1]);Q[(g>>2)+h]=0;try{var r=f(h,g);if(!(noExitRuntime||0 track.stop()); video.srcObject = null; } diff --git a/zbar/qr.cpp b/zbar/qr.cpp index b0d7de8..ec41ada 100644 --- a/zbar/qr.cpp +++ b/zbar/qr.cpp @@ -65,15 +65,30 @@ extern "C" { } if (symb_p == image->symbol_end()) return NULL; - std::cout << "decoded " << symb_p->get_type_name() << std::endl; - std::cout << symb_p->get_data() << std::endl; std::string data = symb_p->get_data(); char* str = (char*)malloc(data.size() + 1); strcpy(str, data.c_str()); - ++ symb_p; return str; } + /** + * Returns the type of the QR code + * + * @return char* containing the type of QR code + */ + EXPORT const char* getResultType() { + if (!image) { + std::cerr << "Call triggerDecode first to get scan result\n"; + return NULL; + } + if (symb_p == image->symbol_end()) + return NULL; + std::string type = symb_p->get_type_name(); + char* str = (char*)malloc(type.size() + 1); + strcpy(str, type.c_str()); + ++ symb_p; + return str; + } } int main(int argc, char** argv) { @@ -89,5 +104,4 @@ int main(int argc, char** argv) { scanner.set_config(zbar::ZBAR_CODE128, zbar::ZBAR_CFG_ENABLE, 1); scanner.set_config(zbar::ZBAR_CODABAR, zbar::ZBAR_CFG_ENABLE, 1); scanner.set_config(zbar::ZBAR_DATABAR, zbar::ZBAR_CFG_ENABLE, 1); - std::cout << "QR/Barcode scanner initialized" << std::endl; }