mrz_scan.ts (1962B)
1 import { IDDocumentMRZScan, MRZInfo } from "#core/application/id_document/mrzscan.ts"; 2 import { parse } from "mrz"; 3 4 const PREFIX = "data:image/png;base64,"; 5 6 export class TesseractIDDocumentMRZScanAdapter implements IDDocumentMRZScan { 7 constructor(private readonly path: string) { 8 } 9 10 async scan(image: string): Promise<MRZInfo> { 11 if (!image.startsWith(PREFIX)) { 12 throw new Error("invalid image"); 13 } 14 15 try { 16 const buffer = Uint8Array.from( 17 atob(image.substring(PREFIX.length)), 18 (c) => c.charCodeAt(0), 19 ); 20 const command = new Deno.Command(this.path, { 21 args: [ 22 "-l", 23 "ocrb", 24 "stdin", 25 "stdout", 26 ], 27 env: { 28 TESSDATA_PREFIX: new URL("./models", import.meta.url).pathname, 29 }, 30 stdin: "piped", 31 stderr: "null", 32 stdout: "piped", 33 }); 34 const process = command.spawn(); 35 const writer = process.stdin.getWriter(); 36 await writer.ready; 37 await writer.write(buffer); 38 await writer.close(); 39 const content = new TextDecoder().decode( 40 (await process.output()).stdout!, 41 ); 42 43 const lines = content 44 .split("\n") 45 .filter((line) => line.includes("<") && !line.includes(" ")); 46 47 const result = parse( 48 lines, 49 { autocorrect: true }, 50 ); 51 52 if (result.valid) { 53 console.log(result.fields); 54 return { 55 firstName: result.fields.firstName!, 56 lastName: result.fields.lastName!, 57 birthDate: new Date( 58 result.fields.birthDate!.split(/([0-9]{2})/).filter((i) => !!i) 59 .join("/"), 60 ), 61 sex: result.fields.sex!, 62 nationality: result.fields.nationality!, 63 country: result.fields.issuingState!, 64 }; 65 } 66 throw new Error("Invalid scan"); 67 } catch (cause) { 68 throw new Error("Invalid MRZ", { cause }); 69 } 70 } 71 }