UNPKG

id-scanner-lib

Version:

Browser-based ID card, QR code, and face recognition scanner with liveness detection

248 lines (209 loc) 5.47 kB
/** * @file 性能优化工具 * @description 提供性能优化相关的工具函数 * @module utils/performance */ /** * LRU缓存实现 */ export class LRUCache<K, V> { private capacity: number; private cache: Map<K, V>; /** * 构造函数 * @param capacity 缓存容量 */ constructor(capacity: number = 100) { this.capacity = capacity; this.cache = new Map<K, V>(); } /** * 获取缓存项 * @param key 键 * @returns 值,如果不存在则返回undefined */ get(key: K): V | undefined { if (!this.cache.has(key)) { return undefined; } // 获取值 const value = this.cache.get(key)!; // 删除旧位置 this.cache.delete(key); // 添加到最新位置 this.cache.set(key, value); return value; } /** * 设置缓存项 * @param key 键 * @param value 值 */ set(key: K, value: V): void { // 如果已存在,先删除 if (this.cache.has(key)) { this.cache.delete(key); } // 如果缓存已满,删除最旧的项 else if (this.cache.size >= this.capacity) { this.cache.delete(this.cache.keys().next().value as K); } // 添加新项 this.cache.set(key, value); } /** * 检查键是否存在 * @param key 键 * @returns 是否存在 */ has(key: K): boolean { return this.cache.has(key); } /** * 删除缓存项 * @param key 键 * @returns 是否成功删除 */ delete(key: K): boolean { return this.cache.delete(key); } /** * 清空缓存 */ clear(): void { this.cache.clear(); } /** * 获取缓存大小 */ get size(): number { return this.cache.size; } /** * 获取所有键 */ keys(): IterableIterator<K> { return this.cache.keys(); } /** * 获取所有值 */ values(): IterableIterator<V> { return this.cache.values(); } /** * 获取所有项 */ entries(): IterableIterator<[K, V]> { return this.cache.entries(); } } /** * 计算图像指纹 * @param imageData 图像数据 * @returns 图像指纹 */ export function calculateImageFingerprint(imageData: ImageData): string { const { width, height, data } = imageData; // 缩小图像以加快计算速度 const scale = Math.min(1, 32 / Math.max(width, height)); const scaledWidth = Math.max(8, Math.floor(width * scale)); const scaledHeight = Math.max(8, Math.floor(height * scale)); // 创建缩小的图像 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (!ctx) { throw new Error('无法创建Canvas上下文'); } // 设置canvas尺寸 canvas.width = scaledWidth; canvas.height = scaledHeight; // 创建临时canvas存储原始ImageData const tempCanvas = document.createElement('canvas'); const tempCtx = tempCanvas.getContext('2d'); if (!tempCtx) { throw new Error('无法创建临时Canvas上下文'); } tempCanvas.width = width; tempCanvas.height = height; tempCtx.putImageData(imageData, 0, 0); // 绘制缩小的图像 ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, scaledWidth, scaledHeight); // 获取缩小的图像数据 const scaledImageData = ctx.getImageData(0, 0, scaledWidth, scaledHeight); // 计算灰度值 const grayValues = new Uint8Array(scaledWidth * scaledHeight); for (let i = 0; i < scaledWidth * scaledHeight; i++) { const idx = i * 4; grayValues[i] = Math.round( 0.299 * scaledImageData.data[idx] + 0.587 * scaledImageData.data[idx + 1] + 0.114 * scaledImageData.data[idx + 2] ); } // 计算平均值 let sum = 0; for (let i = 0; i < grayValues.length; i++) { sum += grayValues[i]; } const avg = sum / grayValues.length; // 计算哈希值 let hash = ''; for (let i = 0; i < grayValues.length; i++) { hash += grayValues[i] >= avg ? '1' : '0'; } return hash; } /** * 防抖函数 * @param func 要执行的函数 * @param wait 等待时间(毫秒) * @returns 防抖处理后的函数 */ export function debounce<T extends (...args: any[]) => any>( func: T, wait: number ): (...args: Parameters<T>) => void { let timeout: number | null = null; return function(this: any, ...args: Parameters<T>): void { const later = () => { timeout = null; func.apply(this, args); }; if (timeout !== null) { clearTimeout(timeout); } timeout = window.setTimeout(later, wait) as unknown as number; }; } /** * 节流函数 * @param func 要执行的函数 * @param limit 时间限制(毫秒) * @returns 节流处理后的函数 */ export function throttle<T extends (...args: any[]) => any>( func: T, limit: number ): (...args: Parameters<T>) => void { let inThrottle = false; let lastFunc: number | null = null; let lastRan: number | null = null; return function(this: any, ...args: Parameters<T>): void { if (!inThrottle) { func.apply(this, args); lastRan = Date.now(); inThrottle = true; } else { if (lastFunc !== null) { clearTimeout(lastFunc); } lastFunc = window.setTimeout(() => { if (lastRan !== null && Date.now() - lastRan >= limit) { func.apply(this, args); lastRan = Date.now(); } }, limit - (lastRan !== null ? Date.now() - lastRan : 0)) as unknown as number; } }; }