accuraidscanplugin 1.0.25 → 1.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/accura.xml +33314 -0
- package/accuraface2.js +267 -0
- package/build/accuramain.js +1 -1
- package/package.json +5 -4
- package/{src → public/accura}/js.json +818 -818
package/accuraface2.js
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
function Utils(errorOutputId) {
|
|
2
|
+
// eslint-disable-line no-unused-vars
|
|
3
|
+
let self = this;
|
|
4
|
+
this.errorOutput = document.getElementById(errorOutputId);
|
|
5
|
+
this.apiKey = "168508101488d7JV8yvF32yRGRti0hyatBHFwev0KInaUAgtGv";
|
|
6
|
+
|
|
7
|
+
const OPENCV_URL = "opencv.js";
|
|
8
|
+
this.loadOpenCv = function (onloadCallback) {
|
|
9
|
+
let script = document.createElement("script");
|
|
10
|
+
script.setAttribute("async", "");
|
|
11
|
+
script.setAttribute("type", "text/javascript");
|
|
12
|
+
script.addEventListener("load", () => {
|
|
13
|
+
if (cv.getBuildInformation) {
|
|
14
|
+
console.log(cv.getBuildInformation());
|
|
15
|
+
onloadCallback();
|
|
16
|
+
} else {
|
|
17
|
+
// WASM
|
|
18
|
+
cv["onRuntimeInitialized"] = () => {
|
|
19
|
+
console.log(cv.getBuildInformation());
|
|
20
|
+
onloadCallback();
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
script.addEventListener("error", () => {
|
|
25
|
+
self.printError("Failed to load " + OPENCV_URL);
|
|
26
|
+
});
|
|
27
|
+
script.src = OPENCV_URL;
|
|
28
|
+
let node = document.getElementsByTagName("script")[0];
|
|
29
|
+
node.parentNode.insertBefore(script, node);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
this.createFileFromUrl = function (path, url, callback) {
|
|
33
|
+
let request = new XMLHttpRequest();
|
|
34
|
+
request.open("GET", url, true);
|
|
35
|
+
request.responseType = "arraybuffer";
|
|
36
|
+
request.onload = function (ev) {
|
|
37
|
+
if (request.readyState === 4) {
|
|
38
|
+
if (request.status === 200) {
|
|
39
|
+
let data = new Uint8Array(request.response);
|
|
40
|
+
cv.FS_createDataFile("/", path, data, true, false, false);
|
|
41
|
+
callback();
|
|
42
|
+
} else {
|
|
43
|
+
self.printError(
|
|
44
|
+
"Failed to load " + url + " status: " + request.status
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
request.send();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
this.loadImageToCanvas = function (url, cavansId) {
|
|
53
|
+
let canvas = document.getElementById(cavansId);
|
|
54
|
+
let ctx = canvas.getContext("2d");
|
|
55
|
+
let img = new Image();
|
|
56
|
+
img.crossOrigin = "anonymous";
|
|
57
|
+
img.onload = function () {
|
|
58
|
+
canvas.width = img.width;
|
|
59
|
+
canvas.height = img.height;
|
|
60
|
+
ctx.drawImage(img, 0, 0, img.width, img.height);
|
|
61
|
+
};
|
|
62
|
+
img.src = url;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
this.executeCode = function (textAreaId) {
|
|
66
|
+
try {
|
|
67
|
+
this.clearError();
|
|
68
|
+
let code = document.getElementById(textAreaId).value;
|
|
69
|
+
eval(code);
|
|
70
|
+
} catch (err) {
|
|
71
|
+
this.printError(err);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
this.clearError = function () {
|
|
76
|
+
this.errorOutput.innerHTML = "";
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
this.printError = function (err) {
|
|
80
|
+
if (typeof err === "undefined") {
|
|
81
|
+
err = "";
|
|
82
|
+
} else if (typeof err === "number") {
|
|
83
|
+
if (!isNaN(err)) {
|
|
84
|
+
if (typeof cv !== "undefined") {
|
|
85
|
+
err = "Exception: " + cv.exceptionFromPtr(err).msg;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} else if (typeof err === "string") {
|
|
89
|
+
let ptr = Number(err.split(" ")[0]);
|
|
90
|
+
if (!isNaN(ptr)) {
|
|
91
|
+
if (typeof cv !== "undefined") {
|
|
92
|
+
err = "Exception: " + cv.exceptionFromPtr(ptr).msg;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} else if (err instanceof Error) {
|
|
96
|
+
err = err.stack.replace(/\n/g, "<br>");
|
|
97
|
+
}
|
|
98
|
+
this.errorOutput.innerHTML = err;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
this.loadCode = function (scriptId, textAreaId) {
|
|
102
|
+
let scriptNode = document.getElementById(scriptId);
|
|
103
|
+
let textArea = document.getElementById(textAreaId);
|
|
104
|
+
if (scriptNode.type !== "text/code-snippet") {
|
|
105
|
+
throw Error("Unknown code snippet type");
|
|
106
|
+
}
|
|
107
|
+
textArea.value = scriptNode.text.replace(/^\n/, "");
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
this.addFileInputHandler = function (fileInputId, canvasId) {
|
|
111
|
+
let inputElement = document.getElementById(fileInputId);
|
|
112
|
+
inputElement.addEventListener(
|
|
113
|
+
"change",
|
|
114
|
+
(e) => {
|
|
115
|
+
let files = e.target.files;
|
|
116
|
+
if (files.length > 0) {
|
|
117
|
+
let imgUrl = URL.createObjectURL(files[0]);
|
|
118
|
+
self.loadImageToCanvas(imgUrl, canvasId);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
false
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
function onVideoCanPlay() {
|
|
126
|
+
if (self.onCameraStartedCallback) {
|
|
127
|
+
self.onCameraStartedCallback(self.stream, self.video);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
this.startCamera = function (resolution, callback, videoId) {
|
|
132
|
+
const constraints = {
|
|
133
|
+
qvga: { width: { exact: 320 }, height: { exact: 240 } },
|
|
134
|
+
vga: { width: { exact: 640 }, height: { exact: 480 } },
|
|
135
|
+
};
|
|
136
|
+
let video = document.getElementById(videoId);
|
|
137
|
+
if (!video) {
|
|
138
|
+
video = document.createElement("video");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let videoConstraint = constraints[resolution];
|
|
142
|
+
if (!videoConstraint) {
|
|
143
|
+
videoConstraint = true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
navigator.mediaDevices
|
|
147
|
+
.getUserMedia({ video: videoConstraint, audio: false })
|
|
148
|
+
.then(function (stream) {
|
|
149
|
+
video.srcObject = stream;
|
|
150
|
+
video.play();
|
|
151
|
+
self.video = video;
|
|
152
|
+
self.stream = stream;
|
|
153
|
+
self.onCameraStartedCallback = callback;
|
|
154
|
+
video.addEventListener("canplay", onVideoCanPlay, false);
|
|
155
|
+
})
|
|
156
|
+
.catch(function (err) {
|
|
157
|
+
self.printError("Camera Error: " + err.name + " " + err.message);
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
this.stopCamera = function () {
|
|
162
|
+
if (this.video) {
|
|
163
|
+
this.video.pause();
|
|
164
|
+
this.video.srcObject = null;
|
|
165
|
+
this.video.removeEventListener("canplay", onVideoCanPlay);
|
|
166
|
+
}
|
|
167
|
+
if (this.stream) {
|
|
168
|
+
this.stream.getVideoTracks()[0].stop();
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
this.captureImage = function (canvasId) {
|
|
173
|
+
let canvas = document.getElementById(canvasId);
|
|
174
|
+
let dataUrl = canvas.toDataURL("image/jpeg");
|
|
175
|
+
return dataUrl;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
this.stringFunction = function (dynamicString) {
|
|
179
|
+
console.log("Dynamic string:", dynamicString);
|
|
180
|
+
|
|
181
|
+
document.getElementById("status-text").innerText = dynamicString;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
this.captureAndSend = function () {
|
|
185
|
+
let video = document.getElementById("cam_input");
|
|
186
|
+
let canvas = document.getElementById("canvas_output");
|
|
187
|
+
|
|
188
|
+
// Hide the video and show the canvas after capturing the photo
|
|
189
|
+
video.style.display = "none";
|
|
190
|
+
canvas.style.display = "block";
|
|
191
|
+
isCanvasVisible = true;
|
|
192
|
+
|
|
193
|
+
// Create a canvas element to temporarily hold the image data
|
|
194
|
+
let tempCanvas = document.createElement("canvas");
|
|
195
|
+
tempCanvas.width = video.videoWidth;
|
|
196
|
+
tempCanvas.height = video.videoHeight;
|
|
197
|
+
let ctx = tempCanvas.getContext("2d");
|
|
198
|
+
ctx.drawImage(video, 0, 0, tempCanvas.width, tempCanvas.height);
|
|
199
|
+
|
|
200
|
+
// Draw the oval shape on the temporary canvas
|
|
201
|
+
ctx.save();
|
|
202
|
+
ctx.beginPath();
|
|
203
|
+
ctx.moveTo(tempCanvas.width / 2, 0);
|
|
204
|
+
ctx.bezierCurveTo(
|
|
205
|
+
tempCanvas.width,
|
|
206
|
+
0,
|
|
207
|
+
tempCanvas.width,
|
|
208
|
+
tempCanvas.height,
|
|
209
|
+
tempCanvas.width / 2,
|
|
210
|
+
tempCanvas.height
|
|
211
|
+
);
|
|
212
|
+
ctx.bezierCurveTo(0, tempCanvas.height, 0, 0, tempCanvas.width / 2, 0);
|
|
213
|
+
ctx.clip();
|
|
214
|
+
ctx.drawImage(tempCanvas, 0, 0);
|
|
215
|
+
ctx.restore();
|
|
216
|
+
|
|
217
|
+
let imageDataUrl = tempCanvas.toDataURL("image/jpeg");
|
|
218
|
+
|
|
219
|
+
// // Check if imageDataUrl is valid
|
|
220
|
+
// if (!imageDataUrl) {
|
|
221
|
+
// console.error("Invalid imageDataUrl");
|
|
222
|
+
// return;
|
|
223
|
+
// }
|
|
224
|
+
|
|
225
|
+
// // Send the captured image to the API
|
|
226
|
+
// fetch("https://accurascan.com/v2/api/liveness", {
|
|
227
|
+
// method: "POST",
|
|
228
|
+
// headers: {
|
|
229
|
+
// "Api-Key": self.apiKey,
|
|
230
|
+
// "Content-Type": "application/json",
|
|
231
|
+
// },
|
|
232
|
+
// body: JSON.stringify({
|
|
233
|
+
// liveness_image: imageDataUrl,
|
|
234
|
+
// }),
|
|
235
|
+
// })
|
|
236
|
+
// .then((response) => {
|
|
237
|
+
// // Check if the response is successful (status code 2xx)
|
|
238
|
+
// if (!response.ok) {
|
|
239
|
+
// throw new Error(
|
|
240
|
+
// `Network response was not ok, status: ${response.status}`
|
|
241
|
+
// );
|
|
242
|
+
// }
|
|
243
|
+
// return response.json(); // Parse response body as JSON
|
|
244
|
+
// })
|
|
245
|
+
// .then(function (data) {
|
|
246
|
+
// console.log("API response:", data);
|
|
247
|
+
|
|
248
|
+
// // Check the "status" property in the data object and display appropriate messages
|
|
249
|
+
// if (data.status === true) {
|
|
250
|
+
// self.stringFunction(
|
|
251
|
+
// "Face detected! Quality: " +
|
|
252
|
+
// data.data.quality +
|
|
253
|
+
// ", Score: " +
|
|
254
|
+
// data.data.score
|
|
255
|
+
// );
|
|
256
|
+
// //When face is detected
|
|
257
|
+
// } else {
|
|
258
|
+
// self.stringFunction("No face detected or other status");
|
|
259
|
+
// // When no face is detected or handle other status scenarios if needed
|
|
260
|
+
// }
|
|
261
|
+
// })
|
|
262
|
+
// .catch((error) => {
|
|
263
|
+
// console.error("Error sending image to API:", error);
|
|
264
|
+
// self.stringFunction("Error sending image to API");
|
|
265
|
+
// });
|
|
266
|
+
};
|
|
267
|
+
}
|
package/build/accuramain.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default class IDCardPlugin{constructor(t,{countryCode:e,cardCode:i,topTextSize:n,topTextColor:s,topTextWeight:a,bottomTextSize:o,bottomTextColor:r,bottomTextWeight:c,bottomTextText:d}){this.callback=t,this.country_code=e,this.card_code=i,this.countriesData=[],this.frontStream=null,this.backStream=null,this.uaParserLoaded="undefined"!=typeof UAParser,this.frontCapture=null,this.backCapture=null,this.result={front:null,back:null},this.topInstructSize=n,this.topInstructColor=s,this.topInstructWeight=a,this.InstructSize=o,this.InstructWeight=c,this.InstructColor=r,this.InstructText=d;const l=document.createElement("script");l.src="./node_modules/accuraidscanplugin/public/libs/piexif.js",document.head.appendChild(l),this.ding=new Audio("./node_modules/accuraidscanplugin/public/audio/ding.mp3"),this.ding.preload="auto",this.audioUnlocked=!1,this.ding.muted=!0;const h=()=>{this.audioUnlocked||(this.ding.play().then((()=>{this.ding.pause(),this.ding.currentTime=0,this.ding.muted=!1,this.audioUnlocked=!0})).catch((()=>{})),document.removeEventListener("click",h))};document.addEventListener("click",h,{once:!0}),this.selectedCard=null,this.init()}async init(){try{const t=await fetch("./node_modules/accuraidscanplugin/src/js.json");if(!t.ok)throw new Error("Failed to load data");this.countriesData=await t.json(),this.loadStyles(),await this.setSelectedCard(),this.startCamera()}catch(t){console.error("Error loading countries data:",t)}}async setSelectedCard(){const t=this.countriesData.find((t=>t.country_code===this.country_code));if(!t)return void console.error(`Country with code ${this.country_code} not found`);let e=null,i=null,n=null;for(const s of t.cards||[])if(s.allcard&&Array.isArray(s.allcard)&&(e=s.allcard.find((t=>t.card_code===this.card_code)),e)){n=s,i=2===s.allcard.length?s.allcard.find((t=>t.card_code!==this.card_code)):null;break}e?this.selectedCard={country_code:t.country_code,card_code:e.card_code,country:t,frontCard:e,backCard:i,requiresBack:!!i}:console.error(`Card with code ${this.card_code} not found for country ${this.country_code}`)}loadStyles(){if(!document.querySelector('link[href*="all.min.css"]')){const t=document.createElement("link");t.rel="stylesheet",t.href="./node_modules/accuraidscanplugin/public/fontawesome-free/css/all.min.css",document.head.appendChild(t)}}startCamera(){if(this.selectedCard)if(this.createCameraUI(),"undefined"!=typeof cv&&cv.getBuildInformation)this.startCameraProcessing();else{const t=document.createElement("script");t.src="./node_modules/accuraidscanplugin/accuraface1.js",t.onload=()=>{cv.onRuntimeInitialized=()=>this.startCameraProcessing()},document.body.appendChild(t)}else console.error("No card selected. Cannot start camera.")}createCameraUI(){this.cameraContainer=document.createElement("div"),this.cameraContainer.className="camera-container",this.cameraContainer.style.position="fixed",this.cameraContainer.style.top="0",this.cameraContainer.style.left="0",this.cameraContainer.style.width="100%",this.cameraContainer.style.height="100%",this.cameraContainer.style.display="flex",this.cameraContainer.style.justifyContent="center",this.cameraContainer.style.alignItems="center",this.cameraContainer.style.background="rgba(0,0,0,0.8)",this.cameraContainer.style.zIndex="2000",document.body.appendChild(this.cameraContainer),this.video=document.createElement("video"),this.video.id="video",this.video.autoplay=!0,this.video.playsInline=!0,this.video.style.width="auto",this.video.style.height="100%",this.video.style.objectFit="cover",this.video.style.position="absolute",this.video.style.top="0",this.video.style.left="50%",this.video.style.transform="translateX(-50%)",this.cameraContainer.appendChild(this.video),this.canvas=document.createElement("canvas"),this.canvas.id="canvas",this.canvas.style.display="none",this.canvas.style.transform="scaleX(-1)",this.cameraContainer.appendChild(this.canvas),this.scanFrame=document.createElement("div"),this.scanFrame.className="scan-frame",this.scanFrame.style.position="absolute",this.scanFrame.style.top="50%",this.scanFrame.style.left="50%",this.scanFrame.style.transform="translate(-50%, -50%)",this.scanFrame.style.border="2px solid red",this.scanFrame.style.boxSizing="border-box",this.scanFrame.style.boxShadow="0 0 0 9999px rgba(0, 0, 0, 0.6)",window.innerWidth<=767?(this.scanFrame.style.width="90vw",this.scanFrame.style.height="50vw",this.scanFrame.style.maxWidth="350px",this.scanFrame.style.maxHeight="200px"):window.innerWidth<=1024?(this.scanFrame.style.width="60vw",this.scanFrame.style.height="40vw",this.scanFrame.style.maxWidth="600px",this.scanFrame.style.maxHeight="400px"):(this.scanFrame.style.width="50vw",this.scanFrame.style.height="30vw",this.scanFrame.style.maxWidth="800px",this.scanFrame.style.maxHeight="500px"),this.cameraContainer.appendChild(this.scanFrame),this.instructionText=document.createElement("div"),this.instructionText.className="instruction-text",this.instructionText.id="instructionText",this.instructionText.textContent=this.InstructText||"Keep Document in Frame",this.instructionText.style.position="absolute",this.instructionText.style.left="50%",this.instructionText.style.transform="translateX(-50%)",this.instructionText.style.padding="8px 12px",this.instructionText.style.borderRadius="6px",this.instructionText.style.pointerEvents="none",this.instructionText.style.textAlign="center",this.instructionText.style.fontSize=this.InstructSize||"0.8rem",this.instructionText.style.fontWeight=this.InstructWeight||"450",this.instructionText.style.width="100%",this.instructionText.style.maxWidth="100%",this.instructionText.style.zIndex="8000",this.instructionText.style.color=this.InstructColor||"#fff",this.instructionText.style.bottom="10%",this.cameraContainer.appendChild(this.instructionText),this.topInstructionText=document.createElement("div"),this.topInstructionText.className="top-instruction-text",this.topInstructionText.id="topInstructionText",this.topInstructionText.style.position="absolute",this.topInstructionText.style.left="50%",this.topInstructionText.style.transform="translateX(-50%)",this.topInstructionText.style.padding="8px 12px",this.topInstructionText.style.borderRadius="6px",this.topInstructionText.style.pointerEvents="none",this.topInstructionText.style.textAlign="center",this.topInstructionText.style.fontSize=this.topInstructSize||"0.8rem",this.topInstructionText.style.fontWeight=this.topInstructWeight||"450",this.topInstructionText.style.width="100%",this.topInstructionText.style.maxWidth="100%",this.topInstructionText.style.zIndex="8000",this.topInstructionText.style.color=this.topInstructColor||"#fff",this.topInstructionText.style.top="10%",this.cameraContainer.appendChild(this.topInstructionText)}startCameraProcessing(){const{country:t,REWARDS:e,frontCard:i,backCard:n,requiresBack:s}=this.selectedCard;let a=i.card_code,o=.12,r=.12;"CLMIDN"===a&&(o=.09,r=.1),"CLMID"===a&&(o=.1,r=.1),"COLPAF"===a&&(o=.09,r=.1),"CLMDL"===a&&(o=.11,r=.1),"COLCIF"===a&&(o=.08,r=.09),"UGNIDF"===a&&(o=.1,r=.12);let c="CLMIDN"===a?`Scan Front Side of ${t.country_name} National ID Card New`:"CLMID"===a?`Scan Front Side of ${t.country_name} National ID Card`:"COLPAF"===a?`Scan Front Side of ${t.country_name}'s Passport`:"CLMDL"===a?`Scan Front Side of ${t.country_name}'s Driving License`:"COLCIF"===a?`Scan Front Side of ${t.country_name}'s Citizen Card`:"UGNIDF"===a?`Scan Front Side of ${t.country_name}'s National ID Card`:"Scanning front side...";this.topInstructionText.textContent=c,this.instructionText.textContent="Keep Document in Frame";const d=new Image;d.src="data:image/jpeg;base64,"+i.card_img;let l=!1,h=0,m=0,u=!1;d.onload=()=>{const e=cv.imread(d);let a=Math.round(.15*e.rows),c=e.roi(new cv.Rect(0,0,e.cols,a));navigator.mediaDevices.getUserMedia({video:{width:{ideal:1920},height:{ideal:1080},facingMode:{ideal:"environment"},frameRate:{ideal:60,max:60}}}).then((a=>{this.frontStream=a,this.video.srcObject=this.frontStream,this.video.addEventListener("loadedmetadata",(()=>{this.canvas.width=this.video.videoWidth,this.canvas.height=this.video.videoHeight}));const d=a=>{if(!this.frontStream||!this.frontStream.active||l)return void requestAnimationFrame(d);const p=this.video.getBoundingClientRect(),y=this.scanFrame.getBoundingClientRect();this.instructionText.style.top=y.bottom+10+"px",this.topInstructionText.style.top=y.top-35+"px";const x=this.video.videoWidth/p.width,C=this.video.videoHeight/p.height,f=(y.left-p.left)*x,g=(y.top-p.top)*C,v=y.width*x,T=y.height*C;if(v>0&&T>0){const a=document.createElement("canvas");a.width=v,a.height=T;a.getContext("2d").drawImage(this.video,f,g,v,T,0,0,v,T);const d=cv.imread(a),p=this.multiScaleTemplateMatch(d,e);if(p.maxVal>=o){const e=this.multiScaleTemplateMatch(d,c);e.maxVal>=r&&(h++,3===h&&(l=!0,this.frontStream.getTracks().forEach((t=>t.stop())),this.processCapturedFrame(a,t,i,p,e,"front").then((()=>{if(s&&n){this.audioUnlocked&&(this.ding.currentTime=0,this.ding.play().catch((()=>{})));const e=document.createElement("div");e.id="flipAnimation",e.innerHTML='<i class="fas fa-id-card"></i>',e.style.animation="flipAnimation 1s linear forwards",e.style.position="absolute",e.style.top="50%",e.style.left="50%",e.style.width="50px",e.style.height="50px",e.style.transform="translate(-50%, -50%)",e.style.fontSize="48px",e.style.color="#e53935",this.cameraContainer.appendChild(e),setTimeout((()=>{e.parentNode===this.cameraContainer&&this.cameraContainer.removeChild(e),this.startBackCameraProcessing(t,n)}),1e3)}}))))}m++,m%20!=0||u||(u=!0,this.instructionText.textContent="Keep Document Near to Camera",setTimeout((()=>{l||(this.instructionText.textContent="Keep Document in Frame"),u=!1}),1200)),d.delete()}requestAnimationFrame(d)};requestAnimationFrame(d)})).catch((t=>{console.error("Front camera error:",t)}))}}startBackCameraProcessing(t,e){let i=.1,n=.12;"UGNIDB"===e.card_code&&(i=.12,n=.12);let s="COLIDB"===e.card_code?`Scan Back Side of ${t.country_name} National ID Card New`:"COLMIDB"===e.card_code?`Scan Back Side of ${t.country_name} National ID Card`:"COLCIB"===e.card_code?`Scan Back Side of ${t.country_name} Citizen Card`:"UGNIDB"===e.card_code?`Scan Back Side of ${t.country_name}'s National ID Card`:"Scanning back side...";this.topInstructionText.textContent=s,this.instructionText.textContent="Keep Document in Frame";const a=new Image;a.src="data:image/jpeg;base64,"+e.card_img;let o=!1,r=0,c=0,d=!1;a.onload=()=>{const s=cv.imread(a);let l=Math.round(.35*s.rows),h=s.roi(new cv.Rect(0,0,s.cols,l));navigator.mediaDevices.getUserMedia({video:{width:{ideal:1920},height:{ideal:1080},facingMode:{ideal:"environment"},frameRate:{ideal:60,max:60}}}).then((a=>{this.backStream=a,this.video.srcObject=this.backStream,this.video.addEventListener("loadedmetadata",(()=>{this.canvas.width=this.video.videoWidth,this.canvas.height=this.video.videoHeight}));const l=a=>{if(!this.backStream||!this.backStream.active||o)return void requestAnimationFrame(l);const m=this.video.getBoundingClientRect(),u=this.scanFrame.getBoundingClientRect();this.instructionText.style.top=u.bottom+10+"px",this.topInstructionText.style.top=u.top-35+"px";const p=this.video.videoWidth/m.width,y=this.video.videoHeight/m.height,x=(u.left-m.left)*p,C=(u.top-m.top)*y,f=u.width*p,g=u.height*y;if(f>0&&g>0){const a=document.createElement("canvas");a.width=f,a.height=g;a.getContext("2d").drawImage(this.video,x,C,f,g,0,0,f,g);const l=cv.imread(a),m=this.multiScaleTemplateMatch(l,s);if(m.maxVal>=i){const i=this.multiScaleTemplateMatch(l,h);i.maxVal>=n&&(r++,3===r&&(o=!0,this.backStream.getTracks().forEach((t=>t.stop())),this.processCapturedFrame(a,t,e,m,i,"back")))}c++,c%20!=0||d||(d=!0,this.instructionText.textContent="Keep Document Near to Camera",setTimeout((()=>{o||(this.instructionText.textContent="Keep Document in Frame"),d=!1}),1200)),l.delete()}requestAnimationFrame(l)};requestAnimationFrame(l)})).catch((t=>{console.error("Back camera error:",t)}))}}multiScaleTemplateMatch(t,e){let i=null,n=1,s=0;const a=new cv.Mat,o=new cv.Mat;cv.resize(e,o,new cv.Size(e.cols,e.rows));const r=new cv.Mat;cv.cvtColor(o,r,cv.COLOR_RGBA2GRAY),cv.Canny(r,r,60,255);for(let e=1;e<=2;e+=.1){const o=new cv.Mat,c=Math.round(t.cols/e),d=Math.round(t.rows/e);cv.resize(t,o,new cv.Size(c,d));let l=o.cols<r.cols||o.rows<r.rows?new cv.Mat:r;if(o.cols<r.cols||o.rows<r.rows){let t=Math.min(o.cols/r.cols,o.rows/r.rows);cv.resize(r,l,new cv.Size(Math.round(r.cols*t),Math.round(r.rows*t)))}const h=new cv.Mat;cv.cvtColor(o,h,cv.COLOR_RGBA2GRAY),cv.Canny(h,h,60,255);try{cv.matchTemplate(h,l,a,cv.TM_CCOEFF_NORMED)}catch(t){console.error("Error in matchTemplate at scale",e,t)}const m=cv.minMaxLoc(a);m.maxVal>s&&(s=m.maxVal,i=m,n=e),h.delete(),(o.cols<r.cols||o.rows<r.rows)&&l.delete(),o.delete()}return o.delete(),r.delete(),a.delete(),{bestMatch:i,bestScale:n,maxVal:s}}async processCapturedFrame(canvas,t,e,i,n,s){this.showLoadingAnimation(),this.instructionText.textContent="Processing...";try{const t=await new Promise((t=>canvas.toBlob(t,"image/jpeg",.9))),e={"0th":{[piexif.ImageIFD.Make]:"AutoID",[piexif.ImageIFD.Model]:"IDDetectionCamera"}},i=piexif.dump(e),n=piexif.insert(i,canvas.toDataURL("image/jpeg",.92));await new Promise((e=>{const i=new FileReader;i.onload=()=>e(i.result),i.readAsDataURL(t)}));"front"===s?this.result.front=n:"back"===s&&(this.result.back=n),!this.selectedCard.requiresBack||this.result.back?(this.callback(this.result),this.hideLoadingAnimation(),setTimeout((()=>{this.stopAllStreams(),this.cameraContainer.remove()}),1e3)):this.hideLoadingAnimation()}catch(t){console.error("Error processing captured frame:",t),this.hideLoadingAnimation(),this.instructionText.textContent="Error processing image. Please try again."}}showLoadingAnimation(){const t=document.createElement("div");t.className="loading-spinner",t.innerHTML='<i class="fas fa-spinner"></i>',t.style.position="absolute",t.style.top="50%",t.style.left="50%",t.style.transform="translate(-50%, -50%)",t.style.zIndex="3500";const e=t.querySelector("i");e.style.fontSize="48px",e.style.animation="spin 1s linear infinite",e.style.color="#e53935",this.cameraContainer.appendChild(t),this.loadingSpinner=t}hideLoadingAnimation(){this.loadingSpinner&&this.loadingSpinner.parentNode===this.cameraContainer&&this.cameraContainer.removeChild(this.loadingSpinner)}stopAllStreams(){this.frontStream&&(this.frontStream.getTracks().forEach((t=>t.stop())),this.frontStream=null),this.backStream&&(this.backStream.getTracks().forEach((t=>t.stop())),this.backStream=null)}}const style=document.createElement("style");style.textContent="\n@keyframes spin { \n from { transform: rotate(0deg); } \n to { transform: rotate(360deg); } \n}\n@keyframes flipAnimation { \n from { transform: translate(-50%, -50%) rotateY(0deg); } \n to { transform: translate(-50%, -50%) rotateY(360deg); } \n}\n",document.head.appendChild(style);
|
|
1
|
+
export default class IDCardPlugin{constructor(t,{countryCode:e,cardCode:i,topTextSize:n,topTextColor:s,topTextWeight:a,bottomTextSize:o,bottomTextColor:r,bottomTextWeight:c,bottomTextText:d}){this.callback=t,this.country_code=e,this.card_code=i,this.countriesData=[],this.frontStream=null,this.backStream=null,this.uaParserLoaded="undefined"!=typeof UAParser,this.frontCapture=null,this.backCapture=null,this.result={front:null,back:null},this.topInstructSize=n,this.topInstructColor=s,this.topInstructWeight=a,this.InstructSize=o,this.InstructWeight=c,this.InstructColor=r,this.InstructText=d;const l=document.createElement("script");l.src="/libs/piexif.js",document.head.appendChild(l),this.ding=new Audio("/audio/ding.mp3"),this.ding.preload="auto",this.audioUnlocked=!1,this.ding.muted=!0;const h=()=>{this.audioUnlocked||(this.ding.play().then((()=>{this.ding.pause(),this.ding.currentTime=0,this.ding.muted=!1,this.audioUnlocked=!0})).catch((()=>{})),document.removeEventListener("click",h))};document.addEventListener("click",h,{once:!0}),this.selectedCard=null,this.init()}async init(){try{const t=await fetch("/accura/js.json");if(!t.ok)throw new Error("Failed to load data");this.countriesData=await t.json(),this.loadStyles(),await this.setSelectedCard(),this.startCamera()}catch(t){console.error("Error loading countries data:",t)}}async setSelectedCard(){const t=this.countriesData.find((t=>t.country_code===this.country_code));if(!t)return void console.error(`Country with code ${this.country_code} not found`);let e=null,i=null,n=null;for(const s of t.cards||[])if(s.allcard&&Array.isArray(s.allcard)&&(e=s.allcard.find((t=>t.card_code===this.card_code)),e)){n=s,i=2===s.allcard.length?s.allcard.find((t=>t.card_code!==this.card_code)):null;break}e?this.selectedCard={country_code:t.country_code,card_code:e.card_code,country:t,frontCard:e,backCard:i,requiresBack:!!i}:console.error(`Card with code ${this.card_code} not found for country ${this.country_code}`)}loadStyles(){if(!document.querySelector('link[href*="all.min.css"]')){const t=document.createElement("link");t.rel="stylesheet",t.href="/fontawesome-free/css/all.min.css",document.head.appendChild(t)}}startCamera(){if(this.selectedCard)if(this.createCameraUI(),"undefined"!=typeof cv&&cv.getBuildInformation)this.startCameraProcessing();else{const t=document.createElement("script");t.src="/accuraface1.js",t.onload=()=>{cv.onRuntimeInitialized=()=>this.startCameraProcessing()},document.body.appendChild(t)}else console.error("No card selected. Cannot start camera.")}createCameraUI(){this.cameraContainer=document.createElement("div"),this.cameraContainer.className="camera-container",this.cameraContainer.style.position="fixed",this.cameraContainer.style.top="0",this.cameraContainer.style.left="0",this.cameraContainer.style.width="100%",this.cameraContainer.style.height="100%",this.cameraContainer.style.display="flex",this.cameraContainer.style.justifyContent="center",this.cameraContainer.style.alignItems="center",this.cameraContainer.style.background="rgba(0,0,0,0.8)",this.cameraContainer.style.zIndex="2000",document.body.appendChild(this.cameraContainer),this.video=document.createElement("video"),this.video.id="video",this.video.autoplay=!0,this.video.playsInline=!0,this.video.style.width="auto",this.video.style.height="100%",this.video.style.objectFit="cover",this.video.style.position="absolute",this.video.style.top="0",this.video.style.left="50%",this.video.style.transform="translateX(-50%)",this.cameraContainer.appendChild(this.video),this.canvas=document.createElement("canvas"),this.canvas.id="canvas",this.canvas.style.display="none",this.canvas.style.transform="scaleX(-1)",this.cameraContainer.appendChild(this.canvas),this.scanFrame=document.createElement("div"),this.scanFrame.className="scan-frame",this.scanFrame.style.position="absolute",this.scanFrame.style.top="50%",this.scanFrame.style.left="50%",this.scanFrame.style.transform="translate(-50%, -50%)",this.scanFrame.style.border="2px solid red",this.scanFrame.style.boxSizing="border-box",this.scanFrame.style.boxShadow="0 0 0 9999px rgba(0, 0, 0, 0.6)",window.innerWidth<=767?(this.scanFrame.style.width="90vw",this.scanFrame.style.height="50vw",this.scanFrame.style.maxWidth="350px",this.scanFrame.style.maxHeight="200px"):window.innerWidth<=1024?(this.scanFrame.style.width="60vw",this.scanFrame.style.height="40vw",this.scanFrame.style.maxWidth="600px",this.scanFrame.style.maxHeight="400px"):(this.scanFrame.style.width="50vw",this.scanFrame.style.height="30vw",this.scanFrame.style.maxWidth="800px",this.scanFrame.style.maxHeight="500px"),this.cameraContainer.appendChild(this.scanFrame),this.instructionText=document.createElement("div"),this.instructionText.className="instruction-text",this.instructionText.id="instructionText",this.instructionText.textContent=this.InstructText||"Keep Document in Frame",this.instructionText.style.position="absolute",this.instructionText.style.left="50%",this.instructionText.style.transform="translateX(-50%)",this.instructionText.style.padding="8px 12px",this.instructionText.style.borderRadius="6px",this.instructionText.style.pointerEvents="none",this.instructionText.style.textAlign="center",this.instructionText.style.fontSize=this.InstructSize||"0.8rem",this.instructionText.style.fontWeight=this.InstructWeight||"450",this.instructionText.style.width="100%",this.instructionText.style.maxWidth="100%",this.instructionText.style.zIndex="8000",this.instructionText.style.color=this.InstructColor||"#fff",this.instructionText.style.bottom="10%",this.cameraContainer.appendChild(this.instructionText),this.topInstructionText=document.createElement("div"),this.topInstructionText.className="top-instruction-text",this.topInstructionText.id="topInstructionText",this.topInstructionText.style.position="absolute",this.topInstructionText.style.left="50%",this.topInstructionText.style.transform="translateX(-50%)",this.topInstructionText.style.padding="8px 12px",this.topInstructionText.style.borderRadius="6px",this.topInstructionText.style.pointerEvents="none",this.topInstructionText.style.textAlign="center",this.topInstructionText.style.fontSize=this.topInstructSize||"0.8rem",this.topInstructionText.style.fontWeight=this.topInstructWeight||"450",this.topInstructionText.style.width="100%",this.topInstructionText.style.maxWidth="100%",this.topInstructionText.style.zIndex="8000",this.topInstructionText.style.color=this.topInstructColor||"#fff",this.topInstructionText.style.top="10%",this.cameraContainer.appendChild(this.topInstructionText)}startCameraProcessing(){const{country:t,REWARDS:e,frontCard:i,backCard:n,requiresBack:s}=this.selectedCard;let a=i.card_code,o=.12,r=.12;"CLMIDN"===a&&(o=.09,r=.1),"CLMID"===a&&(o=.1,r=.1),"COLPAF"===a&&(o=.09,r=.1),"CLMDL"===a&&(o=.11,r=.1),"COLCIF"===a&&(o=.08,r=.09),"UGNIDF"===a&&(o=.1,r=.12);let c="CLMIDN"===a?`Scan Front Side of ${t.country_name} National ID Card New`:"CLMID"===a?`Scan Front Side of ${t.country_name} National ID Card`:"COLPAF"===a?`Scan Front Side of ${t.country_name}'s Passport`:"CLMDL"===a?`Scan Front Side of ${t.country_name}'s Driving License`:"COLCIF"===a?`Scan Front Side of ${t.country_name}'s Citizen Card`:"UGNIDF"===a?`Scan Front Side of ${t.country_name}'s National ID Card`:"Scanning front side...";this.topInstructionText.textContent=c,this.instructionText.textContent="Keep Document in Frame";const d=new Image;d.src="data:image/jpeg;base64,"+i.card_img;let l=!1,h=0,m=0,u=!1;d.onload=()=>{const e=cv.imread(d);let a=Math.round(.15*e.rows),c=e.roi(new cv.Rect(0,0,e.cols,a));navigator.mediaDevices.getUserMedia({video:{width:{ideal:1920},height:{ideal:1080},facingMode:{ideal:"environment"},frameRate:{ideal:60,max:60}}}).then((a=>{this.frontStream=a,this.video.srcObject=this.frontStream,this.video.addEventListener("loadedmetadata",(()=>{this.canvas.width=this.video.videoWidth,this.canvas.height=this.video.videoHeight}));const d=a=>{if(!this.frontStream||!this.frontStream.active||l)return void requestAnimationFrame(d);const p=this.video.getBoundingClientRect(),y=this.scanFrame.getBoundingClientRect();this.instructionText.style.top=y.bottom+10+"px",this.topInstructionText.style.top=y.top-35+"px";const x=this.video.videoWidth/p.width,C=this.video.videoHeight/p.height,f=(y.left-p.left)*x,v=(y.top-p.top)*C,g=y.width*x,T=y.height*C;if(g>0&&T>0){const a=document.createElement("canvas");a.width=g,a.height=T;a.getContext("2d").drawImage(this.video,f,v,g,T,0,0,g,T);const d=cv.imread(a),p=this.multiScaleTemplateMatch(d,e);if(p.maxVal>=o){const e=this.multiScaleTemplateMatch(d,c);e.maxVal>=r&&(h++,3===h&&(l=!0,this.frontStream.getTracks().forEach((t=>t.stop())),this.processCapturedFrame(a,t,i,p,e,"front").then((()=>{if(s&&n){this.audioUnlocked&&(this.ding.currentTime=0,this.ding.play().catch((()=>{})));const e=document.createElement("div");e.id="flipAnimation",e.innerHTML='<i class="fas fa-id-card"></i>',e.style.animation="flipAnimation 1s linear forwards",e.style.position="absolute",e.style.top="50%",e.style.left="50%",e.style.width="50px",e.style.height="50px",e.style.transform="translate(-50%, -50%)",e.style.fontSize="48px",e.style.color="#e53935",this.cameraContainer.appendChild(e),setTimeout((()=>{e.parentNode===this.cameraContainer&&this.cameraContainer.removeChild(e),this.startBackCameraProcessing(t,n)}),1e3)}}))))}m++,m%20!=0||u||(u=!0,this.instructionText.textContent="Keep Document Near to Camera",setTimeout((()=>{l||(this.instructionText.textContent="Keep Document in Frame"),u=!1}),1200)),d.delete()}requestAnimationFrame(d)};requestAnimationFrame(d)})).catch((t=>{console.error("Front camera error:",t)}))}}startBackCameraProcessing(t,e){let i=.1,n=.12;"UGNIDB"===e.card_code&&(i=.12,n=.12);let s="COLIDB"===e.card_code?`Scan Back Side of ${t.country_name} National ID Card New`:"COLMIDB"===e.card_code?`Scan Back Side of ${t.country_name} National ID Card`:"COLCIB"===e.card_code?`Scan Back Side of ${t.country_name} Citizen Card`:"UGNIDB"===e.card_code?`Scan Back Side of ${t.country_name}'s National ID Card`:"Scanning back side...";this.topInstructionText.textContent=s,this.instructionText.textContent="Keep Document in Frame";const a=new Image;a.src="data:image/jpeg;base64,"+e.card_img;let o=!1,r=0,c=0,d=!1;a.onload=()=>{const s=cv.imread(a);let l=Math.round(.35*s.rows),h=s.roi(new cv.Rect(0,0,s.cols,l));navigator.mediaDevices.getUserMedia({video:{width:{ideal:1920},height:{ideal:1080},facingMode:{ideal:"environment"},frameRate:{ideal:60,max:60}}}).then((a=>{this.backStream=a,this.video.srcObject=this.backStream,this.video.addEventListener("loadedmetadata",(()=>{this.canvas.width=this.video.videoWidth,this.canvas.height=this.video.videoHeight}));const l=a=>{if(!this.backStream||!this.backStream.active||o)return void requestAnimationFrame(l);const m=this.video.getBoundingClientRect(),u=this.scanFrame.getBoundingClientRect();this.instructionText.style.top=u.bottom+10+"px",this.topInstructionText.style.top=u.top-35+"px";const p=this.video.videoWidth/m.width,y=this.video.videoHeight/m.height,x=(u.left-m.left)*p,C=(u.top-m.top)*y,f=u.width*p,v=u.height*y;if(f>0&&v>0){const a=document.createElement("canvas");a.width=f,a.height=v;a.getContext("2d").drawImage(this.video,x,C,f,v,0,0,f,v);const l=cv.imread(a),m=this.multiScaleTemplateMatch(l,s);if(m.maxVal>=i){const i=this.multiScaleTemplateMatch(l,h);i.maxVal>=n&&(r++,3===r&&(o=!0,this.backStream.getTracks().forEach((t=>t.stop())),this.processCapturedFrame(a,t,e,m,i,"back")))}c++,c%20!=0||d||(d=!0,this.instructionText.textContent="Keep Document Near to Camera",setTimeout((()=>{o||(this.instructionText.textContent="Keep Document in Frame"),d=!1}),1200)),l.delete()}requestAnimationFrame(l)};requestAnimationFrame(l)})).catch((t=>{console.error("Back camera error:",t)}))}}multiScaleTemplateMatch(t,e){let i=null,n=1,s=0;const a=new cv.Mat,o=new cv.Mat;cv.resize(e,o,new cv.Size(e.cols,e.rows));const r=new cv.Mat;cv.cvtColor(o,r,cv.COLOR_RGBA2GRAY),cv.Canny(r,r,60,255);for(let e=1;e<=2;e+=.1){const o=new cv.Mat,c=Math.round(t.cols/e),d=Math.round(t.rows/e);cv.resize(t,o,new cv.Size(c,d));let l=o.cols<r.cols||o.rows<r.rows?new cv.Mat:r;if(o.cols<r.cols||o.rows<r.rows){let t=Math.min(o.cols/r.cols,o.rows/r.rows);cv.resize(r,l,new cv.Size(Math.round(r.cols*t),Math.round(r.rows*t)))}const h=new cv.Mat;cv.cvtColor(o,h,cv.COLOR_RGBA2GRAY),cv.Canny(h,h,60,255);try{cv.matchTemplate(h,l,a,cv.TM_CCOEFF_NORMED)}catch(t){console.error("Error in matchTemplate at scale",e,t)}const m=cv.minMaxLoc(a);m.maxVal>s&&(s=m.maxVal,i=m,n=e),h.delete(),(o.cols<r.cols||o.rows<r.rows)&&l.delete(),o.delete()}return o.delete(),r.delete(),a.delete(),{bestMatch:i,bestScale:n,maxVal:s}}async processCapturedFrame(canvas,t,e,i,n,s){this.showLoadingAnimation(),this.instructionText.textContent="Processing...";try{const t=await new Promise((t=>canvas.toBlob(t,"image/jpeg",.9))),e={"0th":{[piexif.ImageIFD.Make]:"AutoID",[piexif.ImageIFD.Model]:"IDDetectionCamera"}},i=piexif.dump(e),n=piexif.insert(i,canvas.toDataURL("image/jpeg",.92));await new Promise((e=>{const i=new FileReader;i.onload=()=>e(i.result),i.readAsDataURL(t)}));"front"===s?this.result.front=n:"back"===s&&(this.result.back=n),!this.selectedCard.requiresBack||this.result.back?(this.callback(this.result),this.hideLoadingAnimation(),setTimeout((()=>{this.stopAllStreams(),this.cameraContainer.remove()}),1e3)):this.hideLoadingAnimation()}catch(t){console.error("Error processing captured frame:",t),this.hideLoadingAnimation(),this.instructionText.textContent="Error processing image. Please try again."}}showLoadingAnimation(){const t=document.createElement("div");t.className="loading-spinner",t.innerHTML='<i class="fas fa-spinner"></i>',t.style.position="absolute",t.style.top="50%",t.style.left="50%",t.style.transform="translate(-50%, -50%)",t.style.zIndex="3500";const e=t.querySelector("i");e.style.fontSize="48px",e.style.animation="spin 1s linear infinite",e.style.color="#e53935",this.cameraContainer.appendChild(t),this.loadingSpinner=t}hideLoadingAnimation(){this.loadingSpinner&&this.loadingSpinner.parentNode===this.cameraContainer&&this.cameraContainer.removeChild(this.loadingSpinner)}stopAllStreams(){this.frontStream&&(this.frontStream.getTracks().forEach((t=>t.stop())),this.frontStream=null),this.backStream&&(this.backStream.getTracks().forEach((t=>t.stop())),this.backStream=null)}}const style=document.createElement("style");style.textContent="\n@keyframes spin { \n from { transform: rotate(0deg); } \n to { transform: rotate(360deg); } \n}\n@keyframes flipAnimation { \n from { transform: translate(-50%, -50%) rotateY(0deg); } \n to { transform: translate(-50%, -50%) rotateY(360deg); } \n}\n",document.head.appendChild(style);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "accuraidscanplugin",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.26",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./src/accuraautoocruganda.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"build/accuramain.js",
|
|
11
11
|
"./accuraface1.js",
|
|
12
|
-
"./
|
|
13
|
-
"./public"
|
|
12
|
+
"./accuraface2.js",
|
|
13
|
+
"./public",
|
|
14
|
+
"./accura.xml"
|
|
14
15
|
],
|
|
15
16
|
"keywords": [],
|
|
16
17
|
"author": "",
|
|
@@ -28,4 +29,4 @@
|
|
|
28
29
|
"dependencies": {
|
|
29
30
|
|
|
30
31
|
}
|
|
31
|
-
}
|
|
32
|
+
}
|