node-omron-hvc-p2
Version:
The node-omron-hvc-p2 is a Node.js module which allows you to communicate with the image sensing device "OMRON Human Vision Components (HVC-P2)" through a USB serial port.
601 lines (577 loc) • 14.6 kB
JavaScript
/* ------------------------------------------------------------------
* node-omron-hvc-p2 - HvcP2Image.js
* Date: 2017-06-19
* ---------------------------------------------------------------- */
;
const mFs = require('fs');
let mGd = null;
try {
mGd = require('node-gd');
} catch(e) {}
let mLwip = null;
try {
mLwip = require('lwip');
} catch(e) {}
/* ------------------------------------------------------------------
* Constructor: HvcP2Image()
* ---------------------------------------------------------------- */
const HvcP2Image = function() {
// Plublic properties
// Private properties
this._IMAGE_OPTIONS = {
png: {
compression : 'fast',
interlaced : false,
transparency : 'auto'
},
jpg: {
quality : 100
},
gif: {
colors : 256,
interlaced : false,
threshold : 0
}
};
};
/* ------------------------------------------------------------------
* Method: conv(params, result)
* -params:
* - width | required | Number | Width of image
* - height | required | Number | Height of image
* - pixels | required | Array |
* - type | required | Number | 1: Buffer, 2: Data URL, 3: File
* - format | optional | String | "gif" (default), "jpg", or "png"
* - path | conditional | String | File path with file name (e.g., "/tmp/image.png")
* - maker | optional | Boolean | true or false (default)
* ---------------------------------------------------------------- */
HvcP2Image.prototype.conv = function(params, result) {
let promise = new Promise((resolve, reject) => {
if(!mGd && !mLwip) {
reject(new Error('The node module `node-gd` or `lwip` must be installed.'));
return;
}
let p = {};
// width
if('width' in params) {
let v = params['width'];
if(typeof(v) === 'number' && v % 1 === 0 && v > 0) {
p['width'] = v;
} else {
reject(new Error('The parameter `width` must be an integer grater than 0.'));
return;
}
} else {
reject(new Error('The parameter `width` is required.'));
return;
}
// height
if('height' in params) {
let v = params['height'];
if(typeof(v) === 'number' && v % 1 === 0 && v > 0) {
p['height'] = v;
} else {
reject(new Error('The parameter `height` must be an integer grater than 0.'));
return;
}
} else {
reject(new Error('The parameter `height` is required.'));
return;
}
// pixels
if('pixels' in params) {
let v = params['pixels']
if(Array.isArray(v) && v.length > 0) {
p['pixels'] = v;
} else {
reject(new Error('The parameter `pixels` must be an Array object.'));
return;
}
} else {
reject(new Error('The parameter `pixels` is required.'));
return;
}
// type
if('type' in params) {
let v = params['type'];
if(typeof(v) === 'number' && v.toString().match(/^(1|2|3)$/)) {
p['type'] = v;
} else {
reject(new Error('The parameter `type` must be 1, 2, or 3.'));
return;
}
} else {
reject(new Error('The parameter `type` is required.'));
return;
}
// format
if('format' in params) {
let v = params['format'];
if(typeof(v) === 'string' && v.match(/^(gif|jpg|png)$/)) {
p['format'] = v;
} else {
reject(new Error('The parameter `format` must be "gif", "jpg", or "png".'));
return;
}
} else {
p['format'] = 'gif';
}
// path
if(p['type'] === 3) {
if('path' in params) {
let v = params['path'];
if(typeof(v) === 'string' && v !== '') {
p['path'] = v;
} else {
reject(new Error('The parameter `path` is invalid.'));
return;
}
} else {
reject(new Error('The parameter `path` is required.'));
return;
}
}
// marker
if('marker' in params) {
let v = params['marker'];
if(typeof(v) === 'boolean') {
p['marker'] = v;
} else {
reject(new Error('The parameter `marker` must be Boolean.'));
return;
}
} else {
p['marker'] = false;
}
if(mGd) {
this._convArrayToImageGd(p, result).then((result) => {
resolve(result);
}).catch((error) => {
reject(error);
});
} else if(mLwip) {
this._convArrayToImageLwip(p, result).then((result) => {
resolve(result);
}).catch((error) => {
reject(error);
});
} else {
reject(new Error('The node module `node-gd` or `lwip` must be installed.'));
return;
}
});
return promise;
};
HvcP2Image.prototype._convArrayToImageGd = function(p, result) {
let promise = new Promise((resolve, reject) => {
mGd.createTrueColor(p['width'], p['height'], (error, image) => {
let left = 0;
let top = 0;
let index = 0;
p['pixels'].forEach((v, i) => {
let color = mGd.trueColor(v, v, v);
image.setPixel(left, top, color)
left ++;
if(left >= p['width']) {
left = 0;
top ++;
}
});
if(p['marker'] === true) {
let w = 1600;
let h = 1200;
if(p['width'] < p['height']) {
w = 1200;
h = 1600;
}
if('hand' in result) {
result['hand'].forEach((o) => {
let x = o['x'];
let y = o['y'];
let s = o['size'];
let sh = s / 2;
let color = 0xffff00;
image.rectangle(
Math.round(p['width'] * (x - sh) / w),
Math.round(p['height'] * (y - sh) / h),
Math.round(p['width'] * (x + sh) / w),
Math.round(p['height'] * (y + sh) / h),
color
);
});
}
if('body' in result) {
result['body'].forEach((o) => {
let x = o['x'];
let y = o['y'];
let s = o['size'];
let sh = s / 2;
let color = 0x00ff00;
image.rectangle(
Math.round(p['width'] * (x - sh) / w),
Math.round(p['height'] * (y - sh) / h),
Math.round(p['width'] * (x + sh) / w),
Math.round(p['height'] * (y + sh) / h),
color
);
});
}
if('face' in result) {
result['face'].forEach((o) => {
if('face' in o) {
let x = o['face']['x'];
let y = o['face']['y'];
let s = o['face']['size'];
let sh = s / 2;
let color = 0x00ff00;
if('gender' in o) {
if(o['gender']['gender'] === 1) {
color = 0x0000ff;
} else if(o['gender']['gender'] === 0) {
color = 0xff0000;
}
}
let x1 = Math.round(p['width'] * (x - sh) / w);
let y1 = Math.round(p['height'] * (y - sh) / h);
let x2 = Math.round(p['width'] * (x + sh) / w);
let y2 = Math.round(p['height'] * (y + sh) / h);
image.rectangle(x1, y1, x2, y2, color);
if('age' in o) {
let string = 'Age:' + o['age']['age'].toString();
let font = '/usr/share/fonts/truetype/freefont/FreeMono.ttf';
if(mFs.existsSync(font)) {
image.stringFT(color, font, 12, 0, x1, y1-4, string, false);
}
}
}
});
}
}
let fpath = 'image.tmp';
if(p['type'] === 3) {
fpath = p['path'];
}
let saveFile = null;
if(p['format'] === 'gif') {
saveFile = (cb) => {
image.saveGif(fpath, (error) => {
cb(error);
});
};
} else if(p['format'] === 'jpg') {
saveFile = (cb) => {
let q = this._IMAGE_OPTIONS['jpg']['quality'];
image.saveJpeg(fpath, q, (error) => {
cb(error);
});
};
} else if(p['format'] === 'png') {
saveFile = (cb) => {
image.savePng(fpath, 3, (error) => {
cb(error);
});
};
}
saveFile((error) => {
image.destroy();
if(error) {
reject(error);
return;
}
if(p['type'] === 1 || p['type'] === 2) {
mFs.open(fpath, 'r', (error, fd) => {
if(error) {
reject(error);
return;
}
mFs.fstat(fd, (error, stats) => {
let fsize = stats['size'];
let buf = Buffer.alloc(fsize);
mFs.read(fd, buf, 0, fsize, 0, (error, bytes, buffer) => {
mFs.close(fd, () => {
if(error) {
reject(error);
return;
}
if(p['type'] === 1) {
resolve(buffer);
} else if(p['type'] === 2) {
resolve('data:image/' + p['format'] + ';base64,' + buffer.toString('base64'));
}
});
});
});
});
} else {
resolve();
}
});
});
});
return promise;
};
HvcP2Image.prototype._convArrayToImageLwip = function(p, result) {
let promise = new Promise((resolve, reject) => {
mLwip.create(p['width'], p['height'], {r: 0, g: 0, b: 0, a: 0}, (error, image) => {
if(error) {
reject(error);
return;
}
let left = 0;
let top = 0;
let index = 0;
let setPixel = (cb) => {
let g = p['pixels'][index];
index ++;
image.setPixel(left, top, [g, g, g, 100], (e, img) => {
image = img;
left ++;
if(left >= p['width']) {
left = 0;
top ++;
}
if(top >= p['height']) {
if(p['marker'] === true) {
this._convArrayToImageLwipMarkers(image, p, result, () => {
cb();
});
} else {
cb();
}
} else {
setPixel(cb);
}
});
};
setPixel(() => {
if(p['type'] === 1 || p['type'] === 2) {
image.toBuffer(p['format'], this._IMAGE_OPTIONS[p['format']], (error, buf) => {
if(error) {
reject(error);
} else {
if(p['type'] === 1) {
resolve(buf);
} else if(p['type'] === 2) {
resolve('data:image/' + p['format'] + ';base64,' + buf.toString('base64'));
}
}
});
} else if(p['type'] === 3) {
image.writeFile(p['path'], p['format'], this._IMAGE_OPTIONS[p['format']], (error, buf) => {
if(error) {
reject(error);
} else {
resolve();
}
});
}
});
});
});
return promise;
};
HvcP2Image.prototype._convArrayToImageLwipMarkers = function(image, p, result, cb) {
let w = 1600;
let h = 1200;
if(p['width'] < p['height']) {
w = 1200;
h = 1600;
}
this._convArrayToImageLwipMarkerFace(image, p, result, w, h).then(() => {
return this._convArrayToImageLwipMarkerHand(image, p, result, w, h);
}).then(() => {
return this._convArrayToImageLwipMarkerBody(image, p, result, w, h);
}).then(() => {
cb();
}).catch((error) => {
throw error;
});
};
HvcP2Image.prototype._convArrayToImageLwipMarkerFace = function(image, p, result, w, h) {
let promise = new Promise((resolve, reject) => {
if(!('face' in result)) {
resolve();
return;
}
let rect_num = result['face'].length;
let rect_idx = 0;
let drawRectangle = (cb) => {
if(rect_idx === rect_num) {
cb();
return;
}
let o = result['face'][rect_idx];
let x = o['face']['x'];
let y = o['face']['y'];
let s = o['face']['size'];
let sh = s / 2;
let color = [0, 255, 0, 100];
if('gender' in o) {
if(o['gender']['gender'] === 1) {
color = [0, 0, 255, 100];
} else if(o['gender']['gender'] === 0) {
color = [255, 0, 0, 100];
}
}
let x1 = Math.round(p['width'] * (x - sh) / w);
let y1 = Math.round(p['height'] * (y - sh) / h);
let x2 = Math.round(p['width'] * (x + sh) / w);
let y2 = Math.round(p['height'] * (y + sh) / h);
this._convArrayToImageLwipMarkerRectangle(image, x1, y1, x2, y2, color).then(() => {
rect_idx ++;
drawRectangle(cb);
}).catch((error) => {
cb(error);
});
};
drawRectangle((error) => {
if(error) {
reject(error);
} else {
resolve();
}
});
});
return promise;
};
HvcP2Image.prototype._convArrayToImageLwipMarkerHand = function(image, p, result, w, h) {
let promise = new Promise((resolve, reject) => {
if(!('hand' in result)) {
resolve();
return;
}
let rect_num = result['hand'].length;
let rect_idx = 0;
let drawRectangle = (cb) => {
if(rect_idx === rect_num) {
cb();
return;
}
let o = result['hand'][rect_idx];
let x = o['x'];
let y = o['y'];
let s = o['size'];
let sh = s / 2;
let color = [255, 255, 0, 100];
let x1 = Math.round(p['width'] * (x - sh) / w);
let y1 = Math.round(p['height'] * (y - sh) / h);
let x2 = Math.round(p['width'] * (x + sh) / w);
let y2 = Math.round(p['height'] * (y + sh) / h);
this._convArrayToImageLwipMarkerRectangle(image, x1, y1, x2, y2, color).then(() => {
rect_idx ++;
drawRectangle(cb);
}).catch((error) => {
cb(error);
});
};
drawRectangle((error) => {
if(error) {
reject(error);
} else {
resolve();
}
});
});
return promise;
};
HvcP2Image.prototype._convArrayToImageLwipMarkerBody = function(image, p, result, w, h) {
let promise = new Promise((resolve, reject) => {
if(!('body' in result)) {
resolve();
return;
}
let rect_num = result['body'].length;
let rect_idx = 0;
let drawRectangle = (cb) => {
if(rect_idx === rect_num) {
cb();
return;
}
let o = result['body'][rect_idx];
let x = o['x'];
let y = o['y'];
let s = o['size'];
let sh = s / 2;
let color = [255, 255, 0, 100];
let x1 = Math.round(p['width'] * (x - sh) / w);
let y1 = Math.round(p['height'] * (y - sh) / h);
let x2 = Math.round(p['width'] * (x + sh) / w);
let y2 = Math.round(p['height'] * (y + sh) / h);
this._convArrayToImageLwipMarkerRectangle(image, x1, y1, x2, y2, color).then(() => {
rect_idx ++;
drawRectangle(cb);
}).catch((error) => {
cb(error);
});
};
drawRectangle((error) => {
if(error) {
reject(error);
} else {
resolve();
}
});
});
return promise;
};
HvcP2Image.prototype._convArrayToImageLwipMarkerRectangle = function(image, x1, y1, x2, y2, color) {
let promise = new Promise((resolve, reject) => {
let x_min = Math.min(x1, x2);
let x_max = Math.max(x1, x2);
let y_min = Math.min(y1, y2);
let y_max = Math.max(y1, y2);
let x = x_min;
let y = y_min;
let side = 'top';
let drawPixel = (cb) => {
if(y > y_max) {
cb();
return;
}
image.setPixel(x, y, color, (e, img) => {
if(e) {
cb(e);
} else {
if(side === 'top') {
x ++;
if(x === x_max) {
side = 'right';
y ++;
}
drawPixel(cb);
} else if(side === 'right') {
y ++;
if(y === y_max) {
side = 'bottom';
x --;
}
drawPixel(cb);
} else if(side === 'bottom') {
x --;
if(x === x_min) {
side = 'left';
y --;
}
drawPixel(cb);
} else if(side === 'left') {
y --;
if(y === y_min) {
cb();
} else {
drawPixel(cb);
}
}
}
});
};
drawPixel((error) => {
if(error) {
reject(error);
} else {
resolve();
}
});
});
return promise;
};
module.exports = new HvcP2Image();