export const normalizeBase64Pure = (input) => { let text = String(input ?? '').trim().replace(/\s/g, '') if (!text) return '' if (/^data:image\/[\w+.-]+;base64,/i.test(text)) { text = text.replace(/^data:image\/[\w+.-]+;base64,/i, '') } return text } /** 补齐 padding,并兼容 URL-safe Base64 */ export const fixBase64ForDecode = (pure) => { let text = String(pure ?? '').replace(/-/g, '+').replace(/_/g, '/') const mod = text.length % 4 if (mod === 2) text += '==' else if (mod === 3) text += '=' return text } export const getMimeTypeFromBase64 = (pure) => { if (pure.startsWith('iVBORw0KGgo')) return 'image/png' return 'image/jpeg' } export const extractImageBase64FromResponse = (result) => { if (result === undefined || result === null) return '' if (typeof result === 'string') return result if (result.imageBase64) return result.imageBase64 if (result.data !== undefined && result.data !== null) { return extractImageBase64FromResponse(result.data) } return '' } export const isWebPlatform = () => { if (typeof window === 'undefined' || typeof document === 'undefined') { return false } try { const sys = uni.getSystemInfoSync() return sys.uniPlatform === 'web' || sys.uniPlatform === 'h5' } catch { return true } } const decodeBase64ToBytes = (pure) => { const normalized = fixBase64ForDecode(pure) const binary = atob(normalized) const bytes = new Uint8Array(binary.length) for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i) } return bytes } const createBlobUrlFromBase64 = (pure, mime) => { const bytes = decodeBase64ToBytes(pure) const blob = new Blob([bytes], { type: mime }) const blobUrl = URL.createObjectURL(blob) return { src: blobUrl, revoke: () => URL.revokeObjectURL(blobUrl), } } const createDataUrlFromBase64 = (pure, mime) => { const normalized = fixBase64ForDecode(pure) return { src: `data:${mime};base64,${normalized}`, revoke: null, } } const tryWebDisplay = (pure, mime, resolve) => { if (typeof window !== 'undefined' && typeof atob === 'function') { try { const blobResult = createBlobUrlFromBase64(pure, mime) console.log('[face-image] 使用 Blob URL 展示') resolve(blobResult) return } catch (error) { console.log('[face-image] Blob URL 创建失败,回退 dataUrl', error) } } console.log('[face-image] 使用 dataUrl 展示') resolve(createDataUrlFromBase64(pure, mime)) } /** * 将 Base64 转为可在页面中展示的图片地址 */ export const loadFaceImageDisplaySrc = (base64Raw) => { return new Promise((resolve, reject) => { const pure = normalizeBase64Pure(base64Raw) if (!pure) { reject(new Error('图片 Base64 为空')) return } const mime = getMimeTypeFromBase64(pure) console.log('[face-image] base64 前缀:', pure.slice(0, 24), 'mime:', mime) if (isWebPlatform()) { tryWebDisplay(pure, mime, resolve) return } if (typeof uni.base64ToTempFilePath === 'function') { uni.base64ToTempFilePath({ base64Data: fixBase64ForDecode(pure), extension: mime === 'image/png' ? 'png' : 'jpg', success: (res) => { console.log('[face-image] 使用临时文件展示:', res.tempFilePath) resolve({ src: res.tempFilePath, revoke: null, }) }, fail: (err) => { console.log('[face-image] base64ToTempFilePath 失败', err) tryWebDisplay(pure, mime, resolve) }, }) return } tryWebDisplay(pure, mime, resolve) }) }