iran-bank-cards-ocr
Version:
A TypeScript library to detect Iranian bank names, logos, and validate card numbers using OCR and Luhn algorithm.
107 lines (94 loc) • 3.79 kB
text/typescript
// Import Tesseract.js for OCR (Optical Character Recognition)
import Tesseract from 'tesseract.js';
// Import utility functions and bank data
import { detectBankInfo, validateCardNumber, preprocessImage } from './utils';
/**
* Capture an image from the user's camera and return it as a data URL.
* @returns {Promise<string>} A promise that resolves to the image data URL.
*/
async function captureImageFromCamera(): Promise<string> {
return new Promise((resolve, reject) => {
const video = document.createElement('video');
video.setAttribute('autoplay', '');
video.setAttribute('playsinline', '');
navigator.mediaDevices
.getUserMedia({ video: { facingMode: 'environment' } })
.then((stream) => {
video.srcObject = stream;
video.onloadedmetadata = () => {
const canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const context = canvas.getContext('2d');
if (context) {
context.drawImage(video, 0, 0, canvas.width, canvas.height);
const imageDataUrl = canvas.toDataURL('image/jpeg');
resolve(imageDataUrl);
// Stop the video stream
stream.getTracks().forEach((track) => track.stop());
} else {
reject(new Error('Could not get canvas context.'));
}
};
})
.catch((error) => {
reject(new Error(`Error accessing camera: ${error.message}`));
});
});
}
/**
* Extract the card number from an image using OCR.
* @param {string} imageDataUrl - The image data URL.
* @returns {Promise<string | null>} A promise that resolves to the extracted card number or null if not found.
*/
async function extractCardNumberFromImage(
imageDataUrl: string
): Promise<string | null> {
try {
// Preprocess the image (crop and resize)
const processedImage = await preprocessImage(imageDataUrl);
// Use Tesseract.js to recognize text from the processed image
const { data } = await Tesseract.recognize(processedImage, 'eng', {
logger: (m) => console.log(m), // Log progress (optional)
});
// Use a regex to find a 16-digit number (assumed to be the card number)
const cardNumberRegex = /\b\d{16}\b/;
const match = data.text.match(cardNumberRegex);
return match ? match[0] : null;
} catch (error) {
console.error('Error processing image:', error);
return null;
}
}
/**
* Main function to capture an image, extract the card number, and detect the bank info.
* @returns {Promise<{ cardNumber: string | null; bankInfo: { en: string; fa: string; logo: string } | null }>} An object containing the card number and bank info (name and logo).
*/
async function readBankCard(): Promise<{
cardNumber: string | null;
bankInfo: { en: string; fa: string; logo: string } | null;
}> {
try {
console.log('Capturing image from camera...');
const imageDataUrl = await captureImageFromCamera();
console.log('Processing image to extract card number...');
const cardNumber = await extractCardNumberFromImage(imageDataUrl);
if (cardNumber && validateCardNumber(cardNumber)) {
const bankInfo = detectBankInfo(cardNumber);
if (bankInfo) {
return { cardNumber, bankInfo };
} else {
console.log('Bank not recognized for the given card number.');
return { cardNumber, bankInfo: null };
}
} else {
console.log('No valid card number found in the image.');
return { cardNumber: null, bankInfo: null };
}
} catch (error) {
console.error('Error reading bank card:', error);
return { cardNumber: null, bankInfo: null };
}
}
// Export the main function
export default readBankCard;