Skip to content

Commit

Permalink
add getScanResult API
Browse files Browse the repository at this point in the history
  • Loading branch information
samsam2310 committed May 30, 2018
1 parent 0184e6e commit f883c08
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 45 deletions.
3 changes: 3 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# .prettierrc
printWidth: 80
singleQuote: True
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,23 @@ ZBAR_NAME = zbar-0.10

all: data/zbar.js

debug: .emmake src/api.cpp
em++ -g2 -s WASM=1 -Wc++11-extensions -o data/zbar.js \
src/api.cpp -I ${ZBAR_NAME}/include/ \
${ZBAR_NAME}/zbar/*.o ${ZBAR_NAME}/zbar/*/*.o \
-s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' \
-s "BINARYEN_METHOD='native-wasm'" \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1 \
-s ASSERTIONS=1 -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=1

data/zbar.js: .emmake src/api.cpp
em++ -Os -s WASM=1 -Wc++11-extensions -o data/zbar.js \
src/api.cpp -I ${ZBAR_NAME}/include/ \
${ZBAR_NAME}/zbar/*.o ${ZBAR_NAME}/zbar/*/*.o \
-s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' \
-s "BINARYEN_METHOD='native-wasm'" \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1

.emmake: ${ZBAR_NAME}/Makefile
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# zbar.wasm

[![Build Status](https://travis-ci.com/samsam2310/zbar.wasm.svg?branch=master)](https://travis-ci.com/samsam2310/zbar.wasm)

A wasm build for C/C++ Zbar bar code scan library.
1 change: 1 addition & 0 deletions data/.npmignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.gitignore
zbar.wasm.pre
76 changes: 42 additions & 34 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
import Module as ApiModule from 'data/zbar'
import * as ApiModule from 'data/zbar';

// async function loadImage(src) {
// // Load image
// const imgBlob = await fetch(src).then(resp => resp.blob());
// const img = await createImageBitmap(imgBlob);
// // Make canvas same size as image
// const canvas = document.createElement('canvas');
// canvas.width = img.width;
// canvas.height = img.height;
// // Draw image onto canvas
// const ctx = canvas.getContext('2d');
// ctx.drawImage(img, 0, 0);
// return ctx.getImageData(0, 0, img.width, img.height);
// }
const utf8BufferToString = (buffer, addr) => {
let end = addr;
while (buffer[end]) {
++end;
}
const str = new Uint8Array(buffer.slice(addr, end));
const encodedString = String.fromCharCode.apply(null, str);
const decodedString = decodeURIComponent(escape(encodedString));
return decodedString;
};

export default Scanner = mixin => {
const mod = ApiModule(mixin);
const api = {
createBuffer: mod.cwrap('createBuffer', 'number', ['number']),
deleteBuffer: mod.cwrap('deleteBuffer', '', ['number']),
scanQrcode: mod.cwrap('scanQrcode', 'number', ['number', 'number', 'number']),
getScanResults: mod.cwrap('getScanResults', '', []),
};
const scanner = {
scanQrcode: imgData => {
const buf = api.createBuffer(image.width, image.height);
mod.HEAP8.set(imgData.data, buf);
api.scanQrcode(buf, image.width, image.height);
api.deleteBuffer(buf);
// TODO: return result
api.getScanResults();
}
};
return new Promise((resolv, reject) => {
mod.then(resolv(scanner));
const Scanner = mixin => {
const mod = ApiModule(mixin);
const api = {
createBuffer: mod.cwrap('createBuffer', 'number', ['number']),
deleteBuffer: mod.cwrap('deleteBuffer', '', ['number']),
scanQrcode: mod.cwrap('scanQrcode', 'number', [
'number',
'number',
'number'
]),
getScanResults: mod.cwrap('getScanResults', 'number', [])
};
const scanner = {
scanQrcode: (imgData, width, height) => {
const buf = api.createBuffer(width * height * 4);
mod.HEAP8.set(imgData, buf);
const results = [];
if (api.scanQrcode(buf, width, height)) {
const res_addr = api.getScanResults();
results.push(utf8BufferToString(mod.HEAP8, res_addr));
api.deleteBuffer(res_addr);
}
return results;
}
};
return new Promise((resolv, reject) => {
mod.then(() => {
resolv(scanner);
});
});
};

export default Scanner;
15 changes: 14 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,18 @@
"bugs": {
"url": "https://github.com/samsam2310/zbar.wasm/issues"
},
"homepage": "https://github.com/samsam2310/zbar.wasm#readme"
"homepage": "https://github.com/samsam2310/zbar.wasm#readme",
"dependencies": {},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"canvas": "^2.0.0-alpha.12",
"node-loader": "^0.6.0",
"prettier": "^1.13.2",
"webpack": "^4.10.2",
"webpack-cli": "^2.1.4"
}
}
39 changes: 29 additions & 10 deletions src/api.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#include <iostream>

#include <emscripten.h>
#include <string.h>
#include <zbar.h>
#include <iostream>

zbar::ImageScanner scanner;
zbar::Image* image = NULL;
zbar::Image::SymbolIterator symb_p;

extern "C" {

Expand All @@ -24,29 +27,45 @@ int scanQrcode(uint8_t* imgBuf, int width, int height) {
for (int j = 0; j < height; ++j) {
uint8_t* pixels = imgBuf + i * height * 4 + j * 4;
int sum = (int)pixels[0] + (int)pixels[1] + (int)pixels[2];
grayImgBuf[i * height + j] = sum / 3;
grayImgBuf[i * height + j] = (uint8_t)(sum / 3);
}
}
free(imgBuf);
if (image) {
delete image;
}
image = new zbar::Image(width, height, "Y800", grayImgBuf, width * height);
return scanner.scan(*image);
int scan_res = scanner.scan(*image);
free(grayImgBuf);
symb_p = image->symbol_begin();
return scan_res;
}

EMSCRIPTEN_KEEPALIVE
void getScanResults() {
for (auto symb_p = image->symbol_begin(); symb_p != image->symbol_end();
++symb_p) {
// do something useful with results
std::cout << "decoded " << symb_p->get_type_name() << " symbol \""
<< symb_p->get_data() << '"' << std::endl;
const char* getScanResults() {
if (!image) {
std::cerr << "Call scanQrcode first to get scan result\n";
return NULL;
}
if (symb_p == image->symbol_end())
return NULL;
std::cout << "decoded " << symb_p->get_type_name() << " symbol \""
<< 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());
// std::cout << "Dbug: ";
// for(const unsigned char* pc = (unsigned char*)data; *pc; ++pc) {
// std::cout << (uint32_t)(*pc) << ' ';
// }
// std::cout << "\n";
++ symb_p;
return str;
}

}

int main(int argc, char** argv) {
scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
scanner.set_config(zbar::ZBAR_QRCODE, zbar::ZBAR_CFG_ENABLE, 1);
std::cout << "Init scanner" << std::endl;
}
3 changes: 3 additions & 0 deletions test/build/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*
*/
!.gitignore
56 changes: 56 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import Scanner from 'index';
import fs from 'fs';
import { createCanvas, loadImage } from 'canvas';

console.log(Scanner);

const readFile = async path => {
fs.open(path, 'r');
};

// const loadImage = async src => {
// // Load image
// const imgBlob = await fetch(src).then(resp => resp.blob());
// const img = await createImageBitmap(imgBlob);
// // Make canvas same size as image
// const canvas = document.createElement('canvas');
// canvas.width = img.width;
// canvas.height = img.height;
// // Draw image onto canvas
// const ctx = canvas.getContext('2d');
// ctx.drawImage(img, 0, 0);
// return ctx.getImageData(0, 0, img.width, img.height);
// }

const loadImageData = async path => {
const img = await loadImage(path);
const canvas = createCanvas();
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
return {
data: canvas.toBuffer('raw'),
height: img.height,
width: img.width
};
};

const scanImage = async (scanner, imagePath) => {
const img = await loadImageData(imagePath);
console.log(scanner.scanQrcode(img.data, img.width, img.height));
};

const main = async () => {
try {
const scanner = await Scanner({ locateFile: file => './data/' + file });
scanImage(scanner, './test/test.png');
scanImage(scanner, './test/test2.png');
scanImage(scanner, './test/test3.png');
} catch (e) {
console.log(e);
} finally {
}
};

main();
File renamed without changes
Binary file added test/test2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/test3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 68 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const path = require('path');
const webpack = require('webpack');

const generateConfig = (
entry,
outputName,
includeFrom,
resolveAlias,
envNames
) => ({
node: {
__dirname: true
},
target: 'node',
watchOptions: {
ignored: '/node_modules/',
poll: true
},
entry: [entry],
output: {
path: path.resolve(__dirname, 'test/build'),
filename: outputName,
},
resolve: {
extensions: ['.js', '.jsx'],
modules: [path.resolve(__dirname, 'node_modules')],
alias: Object.keys(resolveAlias).reduce(function(previous, key) {
previous[key] = path.resolve(__dirname, resolveAlias[key]);
return previous;
}, {})
},
devtool: 'source-map',
plugins: [new webpack.EnvironmentPlugin(envNames)],
module: {
rules: [
{
test: /\.jsx?$/,
include: path.resolve(__dirname, includeFrom),
use: {
loader: 'babel-loader',
options: {
presets: ['babel-preset-env'],
plugins: [
require('babel-plugin-transform-runtime'),
]
}
}
},
{
test: /\.node$/,
use: 'node-loader'
}
]
}
});

module.exports = [
generateConfig(
'./test/test.js',
'build.js',
'test',
{
data: './data',
index: './',
},
[]
)
];

0 comments on commit f883c08

Please sign in to comment.