@gooddollar/react-native-web-facecapture
Version:
92 lines (85 loc) • 3.17 kB
JavaScript
import _get from "lodash/get";
import jpeg from "jpeg-js";
import ImageEditor from "image-js/dist/image";
//{"bounds": {"origin": {"x": 23.156605113636374, "y": 200.6962890625}, "size": {"height": 433.533203125, "width": 300.4031723484848}}, "faceID": 3, "rollAngle": -10.545342445373535, "yawAngle": 8.326322555541992}
const isValidFace = (viewport, face) => {
const facesize = face.bounds;
const requiredWidth = viewport.width * 0.6;
const requiredHeight = viewport.height * 0.6;
const eyesDistance =
_get(face, "leftEyePosition", 0) - _get(face, "rightEyePosition", 0);
if (eyesDistance > 0)
return { ok: false, error: "Eyes distance " + eyesDistance };
if (
facesize.size.width < requiredWidth * 0.7 ||
facesize.size.height < requiredHeight * 0.7
) {
return { ok: false, error: "Move Closer" };
}
if (
facesize.size.width > requiredWidth * 1.3 ||
facesize.size.height > requiredHeight * 1.3
) {
return { ok: false, error: "Move Away" };
}
if (
facesize.origin.x > viewport.width * 0.3 ||
facesize.origin.y > viewport.height * 0.3 ||
facesize.origin.x < viewport.width * 0.15 ||
facesize.origin.y < viewport.height * 0.15
)
return { ok: false, error: "Frame Your Face" };
if (Math.abs(face.yawAngle) > 5 || Math.abs(face.rollAngle) > 5) {
return { ok: false, error: "Look Straight" };
}
if (
_get(face, "smilingProbability", 0) > 0.15 ||
_get(face, "leftEyeOpenProbability", 1) < 0.93 ||
_get(face, "rightEyeOpenProbability", 1) < 0.93
) {
return { ok: false, error: "Kepp Natural Expression" };
}
return { ok: true };
};
const isQualityImage = base64 => {
const start = Date.now();
const imgBuffer = Buffer.from(base64, "base64");
const rawImageData = jpeg.decode(imgBuffer);
const { height, width, data } = rawImageData;
const area = height * width;
const calcAvgColor = () => {
let colorSum = 0;
for (let r, g, b, a, avg, x = 0, len = data.length; x < len; x += 4) {
r = data[x];
g = data[x + 1];
b = data[x + 2];
a = data[x + 3];
avg = Math.floor((r + g + b) / 3);
colorSum += avg;
}
return Math.floor(colorSum / area);
};
const brightness = calcAvgColor();
return { ok: brightness > 80, brightness };
};
const cropToFace = async (img, face, viewport) => {
const edit = await ImageEditor.load(Buffer.from(img.base64, "base64"));
const viewW = viewport.width;
const viewH = viewport.height;
//expand the facebox and get relative img coordinates of face
const imgX = Math.floor((face.bounds.origin.x / viewW) * img.width * 0.8);
const imgY = Math.floor((face.bounds.origin.y / viewH) * img.height * 0.8);
let imgW = Math.floor((face.bounds.size.width / viewW) * img.width);
imgW = imgW + imgX > img.width ? img.width - imgX : imgW;
let imgH = Math.floor((face.bounds.size.height / viewH) * img.height * 1.2);
imgH = imgH + imgY > img.height ? img.height - imgY : imgH;
return edit
.crop({
x: imgX,
y: imgY,
width: imgW,
height: imgH
})
.toBase64("image/jpeg");
};
export { isValidFace, isQualityImage, cropToFace };