/** * 获取位置的异步函数 * H5 端会尝试使用浏览器定位,失败则返回模拟数据 */ export const getLocation = async () => { return new Promise((resolve, reject) => { // #ifdef H5 // H5 端:尝试使用浏览器定位,失败则使用模拟数据 if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( (position) => { resolve({ latitude: position.coords.latitude, longitude: position.coords.longitude, accuracy: position.coords.accuracy, altitude: position.coords.altitude || 0 }); }, (error) => { console.warn('H5 定位失败,使用模拟数据:', error.message); // 返回模拟的经纬度(默认:北京天安门附近) resolve({ latitude: 39.908823, longitude: 116.397470, accuracy: 100, altitude: 0, _isMock: true // 标记为模拟数据 }); }, { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 } ); } else { console.warn('浏览器不支持定位,使用模拟数据'); // 返回模拟的经纬度 resolve({ latitude: 39.908823, longitude: 116.397470, accuracy: 100, altitude: 0, _isMock: true }); } // #endif // #ifndef H5 // App/小程序端:使用原生定位 uni.getLocation({ isHighAccuracy: true, altitude: true, accuracy: 'best', success: (res) => { resolve(res); }, fail: (err) => { console.error('定位失败:', err); // App端定位失败也返回模拟数据,方便调试 resolve({ latitude: 39.908823, longitude: 116.397470, accuracy: 100, altitude: 0, _isMock: true }); } }); // #endif }); } /** * 选择图片(支持多选) * @param {number} count - 最多选择的图片数量,默认1 * @returns {Promise} - 返回选择的图片信息 */ export const chooseImage = async (count = 1) => { return new Promise((resolve, reject) => { uni.chooseImage({ sourceType: ['camera'], // 支持拍照和相册选择, 'album' count: count, // 支持多选 success: (res) => { resolve(res); }, fail: (err) => { reject(err); } }); }); } /** * * @param {*} date * @param {*} format * @returns */ export const formatDate = (date, format = 'YYYY-MM-DD HH:mm:ss') => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return format .replace('YYYY', year) .replace('MM', month) .replace('DD', day) .replace('HH', hours) .replace('mm', minutes) .replace('ss', seconds); } /** * 缓存logo图片的Map */ const logoCache = new Map(); /** * 获取缓存的logo图片路径 * @param {string} logoUrl - logo网络地址 * @returns {Promise} - 返回本地缓存路径 */ export const getCachedLogo = async (logoUrl) => { // 检查缓存中是否已存在 if (logoCache.has(logoUrl)) { console.log('使用缓存的logo:', logoUrl); return logoCache.get(logoUrl); } // #ifdef H5 // H5 使用 fetch 获取 Blob return new Promise((resolve, reject) => { fetch(logoUrl) .then(res => { if (!res.ok) throw new Error("下载失败"); return res.blob(); }) .then(blob => { const objectUrl = URL.createObjectURL(blob); logoCache.set(logoUrl, objectUrl); console.log('H5 缓存 logo:', logoUrl); resolve(objectUrl); }) .catch(err => { console.error('H5 下载logo失败:', err); reject(err); }); }); // #endif // #ifndef H5 // App/小程序使用 uni.downloadFile return new Promise((resolve, reject) => { uni.downloadFile({ url: logoUrl, success: (downloadRes) => { if (downloadRes.statusCode === 200) { console.log('下载并缓存logo:', logoUrl); logoCache.set(logoUrl, downloadRes.tempFilePath); resolve(downloadRes.tempFilePath); } else { reject(new Error("下载失败: " + downloadRes.statusCode)); } }, fail: (err) => { console.error('下载logo失败:', err); reject(err); } }); }); // #endif }; /** * 清除logo缓存 */ export const clearLogoCache = () => { logoCache.clear(); console.log('logo缓存已清除'); }; /** * 获取缓存大小 */ export const getLogoCacheSize = () => { return logoCache.size; }; /** * 处理水印图片导出结果 * @param {string} tempFilePath - 临时文件路径 * @param {object} originalFileSize - 原图文件大小 * @param {number} width - 图片宽度 * @param {number} height - 图片高度 * @param {function} resolve - Promise resolve函数 */ const handleWatermarkExport = async (tempFilePath, originalFileSize, width, height, resolve) => { try { const watermarkFileSize = await getFileSize(tempFilePath); console.log('水印图片文件大小:', watermarkFileSize.sizeKB, 'KB'); resolve({ filePath: tempFilePath, originalSize: { width: width, height: height, fileSize: originalFileSize }, watermarkSize: { width: width, height: height, fileSize: watermarkFileSize } }); } catch (err) { console.error('获取水印图片文件大小失败:', err); // 即使获取文件大小失败,也返回其他信息 resolve({ filePath: tempFilePath, originalSize: { width: width, height: height, fileSize: originalFileSize }, watermarkSize: { width: width, height: height, fileSize: null } }); } }; /** * 计算合适的压缩质量 * @param {number} originalSizeKB - 原图大小(KB) * @returns {number} - 压缩质量(0-1) */ const calculateQuality = (originalSizeKB) => { // 如果文件大小为0或无效,使用默认质量 if (!originalSizeKB || originalSizeKB <= 0) { return 0.8; // 默认中等质量 } if (originalSizeKB < 100) { return 0.9; // 小图片使用高质量 } else if (originalSizeKB < 500) { return 0.8; // 中等图片使用中等质量 } else { return 0.7; // 大图片使用较低质量 } }; /** * 计算合适的输出尺寸 * @param {number} width - 原图宽度 * @param {number} height - 原图高度 * @param {number} maxWidth - 最大宽度限制 * @returns {object} - 输出尺寸 {width, height} */ const calculateOutputSize = (width, height, maxWidth = 1920) => { // 如果图片尺寸已经很小,不需要压缩 if (width <= maxWidth) { return { width, height }; } // 按比例缩放 const ratio = maxWidth / width; return { width: Math.round(width * ratio), height: Math.round(height * ratio) }; }; /** * 获取文件大小 * @param {string|File} filePath - 本地文件路径(App/小程序) 或 File 对象(H5) * @returns {Promise<{size:number,sizeKB:string,sizeMB:string}>} */ const getFileSize = async (filePath) => { return new Promise((resolve, reject) => { // #ifdef H5 try { // H5 情况下,如果传的是 File 对象 if (filePath instanceof File) { const size = filePath.size; resolve({ size: size, sizeKB: (size / 1024).toFixed(2), sizeMB: (size / (1024 * 1024)).toFixed(2) }); } else if (filePath.startsWith('blob:')) { // 如果是blob URL,使用fetch获取blob对象 fetch(filePath) .then(res => res.blob()) .then(blob => { resolve({ size: blob.size, sizeKB: (blob.size / 1024).toFixed(2), sizeMB: (blob.size / (1024 * 1024)).toFixed(2) }); }) .catch(err => { console.error("H5 获取blob文件大小失败:", err); // 如果获取失败,返回默认值 resolve({ size: 0, sizeKB: "0.00", sizeMB: "0.00" }); }); } else { // 如果传入的是普通URL,用 fetch 获取 fetch(filePath, { method: "HEAD" }) .then(res => { const size = res.headers.get("content-length"); if (!size) throw new Error("无法获取文件大小"); resolve({ size: Number(size), sizeKB: (size / 1024).toFixed(2), sizeMB: (size / (1024 * 1024)).toFixed(2) }); }) .catch(err => { console.error("H5 获取文件大小失败:", err); // 如果获取失败,返回默认值 resolve({ size: 0, sizeKB: "0.00", sizeMB: "0.00" }); }); } } catch (err) { console.error("H5 处理异常:", err); // 如果处理异常,返回默认值 resolve({ size: 0, sizeKB: "0.00", sizeMB: "0.00" }); } // #endif // #ifndef H5 // App、小程序端 uni.getFileInfo({ filePath: filePath, success: (res) => { resolve({ size: res.size, sizeKB: (res.size / 1024).toFixed(2), sizeMB: (res.size / (1024 * 1024)).toFixed(2) }); }, fail: (err) => { console.error('获取文件大小失败:', err); reject(err); } }); // #endif }); }; /** * 添加水印到图片 * @param {string} imagePath - 原图片路径 * @param {object} watermarkInfo - 水印信息对象 * @param {string} logoUrl - logo图标网络地址(可选) * @param {number} logoOpacity - logo透明度,范围0-1,默认1(不透明) * @param {number} quality - 压缩质量,范围0-1,默认自动计算 * @param {number} maxWidth - 最大输出宽度,默认1920 * @returns {Promise} - 返回包含水印图片路径和文件大小信息的对象 */ export const addWatermark = async (imagePath, watermarkInfo, logoUrl = null, logoOpacity = 1, quality = null, maxWidth = 1920) => { // #ifdef H5 // H5端水印实现 return new Promise(async (resolve, reject) => { try { // 创建图片对象 const img = new Image(); img.crossOrigin = "anonymous"; img.onload = async () => { try { // 获取原图文件大小 let originalFileSize; try { originalFileSize = await getFileSize(imagePath); console.log('原图文件大小:', originalFileSize.sizeKB, 'KB'); } catch (err) { console.warn('获取原图文件大小失败,使用默认值:', err); originalFileSize = { size: 0, sizeKB: "0.00", sizeMB: "0.00" }; } // 计算压缩质量 const compressionQuality = quality !== null ? quality : calculateQuality(Number(originalFileSize.sizeKB)); console.log('使用压缩质量:', compressionQuality); const { width, height } = img; console.log('原图尺寸:', width, 'x', height); // 计算输出尺寸 const outputSize = calculateOutputSize(width, height, maxWidth); console.log('输出尺寸:', outputSize.width, 'x', outputSize.height); // 创建canvas const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = outputSize.width; canvas.height = outputSize.height; // 绘制原图片到canvas ctx.drawImage(img, 0, 0, outputSize.width, outputSize.height); // 处理水印文本,超过25个字符换行,最多3行 const processText = (text, maxChars = 25, maxLines = 3) => { if (text.length <= maxChars) { return [text]; } const lines = []; let currentLine = ''; let lineCount = 0; for (let i = 0; i < text.length && lineCount < maxLines; i++) { currentLine += text[i]; if (currentLine.length >= maxChars || i === text.length - 1) { lines.push(currentLine); lineCount++; currentLine = ''; // 如果还有剩余字符但已达到最大行数,添加省略号 if (lineCount === maxLines && i < text.length - 1) { lines[lines.length - 1] = lines[lines.length - 1].slice(0, -3) + '...'; break; } } } return lines; }; // 水印内容 const watermarkText = [ `时间: ${watermarkInfo.time}`, `经度: ${watermarkInfo.longitude}`, `维度: ${watermarkInfo.latitude}`, ]; var location = processText("位置: " + watermarkInfo.location); watermarkText.push(...location); var department = processText("部门: " + watermarkInfo.department); watermarkText.push(...department); var status = processText("状态: " + watermarkInfo.status); watermarkText.push(...status); var workers = processText("人员: " + watermarkInfo.workers.join(', ')); watermarkText.push(...workers); var remarks = processText("内容: " + watermarkInfo.remarks); watermarkText.push(...remarks); // 定义绘制文字水印的函数 const drawTextWatermark = async () => { // 计算水印位置(左下角) const padding = 30; const fontSize = 30; const lineHeight = 30; const startX = padding; const startY = outputSize.height - padding - (watermarkText.length * lineHeight); // 设置文字样式 ctx.fillStyle = 'rgba(255, 255, 255, 1)'; ctx.font = `${fontSize}px Arial`; ctx.textBaseline = 'top'; // 绘制文字 watermarkText.forEach((text, index) => { ctx.fillText(text, startX, startY + (index * lineHeight)); }); // 如果有logo,在文字水印上方绘制logo if (logoUrl) { try { // 使用缓存获取logo图片 const cachedLogoPath = await getCachedLogo(logoUrl); // 创建logo图片对象 const logoImg = new Image(); logoImg.crossOrigin = "anonymous"; logoImg.onload = () => { // 动态计算logo位置:在文字水印上方 const logoSize = 200; // logo大小 const logoPadding = 30; const logoX = logoPadding; // logo位置 = 文字水印起始位置 - logo高度 - 间距 const logoY = startY - logoSize - 10; // 设置logo透明度 ctx.globalAlpha = logoOpacity; // 绘制logo ctx.drawImage(logoImg, logoX, logoY, logoSize, logoSize); // 恢复透明度为1(不影响后续绘制) ctx.globalAlpha = 1; // 导出canvas为blob canvas.toBlob((blob) => { const objectUrl = URL.createObjectURL(blob); console.log('H5 水印图片导出成功:', objectUrl); // 获取水印图片文件大小 const watermarkFileSize = { size: blob.size, sizeKB: (blob.size / 1024).toFixed(2), sizeMB: (blob.size / (1024 * 1024)).toFixed(2) }; resolve({ filePath: objectUrl, originalSize: { width: width, height: height, fileSize: originalFileSize }, watermarkSize: { width: outputSize.width, height: outputSize.height, fileSize: watermarkFileSize } }); }, 'image/jpeg', compressionQuality); }; logoImg.onerror = (err) => { console.error('H5 logo加载失败:', err); // logo加载失败时,只绘制文字水印 canvas.toBlob((blob) => { const objectUrl = URL.createObjectURL(blob); console.log('H5 水印图片导出成功(logo加载失败):', objectUrl); const watermarkFileSize = { size: blob.size, sizeKB: (blob.size / 1024).toFixed(2), sizeMB: (blob.size / (1024 * 1024)).toFixed(2) }; resolve({ filePath: objectUrl, originalSize: { width: width, height: height, fileSize: originalFileSize }, watermarkSize: { width: outputSize.width, height: outputSize.height, fileSize: watermarkFileSize } }); }, 'image/jpeg', compressionQuality); }; logoImg.src = cachedLogoPath; } catch (err) { console.error('H5 获取logo失败:', err); // logo获取失败时,只绘制文字水印 canvas.toBlob((blob) => { const objectUrl = URL.createObjectURL(blob); console.log('H5 水印图片导出成功(logo获取失败):', objectUrl); const watermarkFileSize = { size: blob.size, sizeKB: (blob.size / 1024).toFixed(2), sizeMB: (blob.size / (1024 * 1024)).toFixed(2) }; resolve({ filePath: objectUrl, originalSize: { width: width, height: height, fileSize: originalFileSize }, watermarkSize: { width: outputSize.width, height: outputSize.height, fileSize: watermarkFileSize } }); }, 'image/jpeg', compressionQuality); } } else { // 没有logo时,只绘制文字水印 canvas.toBlob((blob) => { const objectUrl = URL.createObjectURL(blob); console.log('H5 水印图片导出成功(无logo):', objectUrl); const watermarkFileSize = { size: blob.size, sizeKB: (blob.size / 1024).toFixed(2), sizeMB: (blob.size / (1024 * 1024)).toFixed(2) }; resolve({ filePath: objectUrl, originalSize: { width: width, height: height, fileSize: originalFileSize }, watermarkSize: { width: outputSize.width, height: outputSize.height, fileSize: watermarkFileSize } }); }, 'image/jpeg', compressionQuality); } }; // 开始绘制文字水印 await drawTextWatermark(); } catch (error) { console.error('H5 处理图片失败:', error); reject(error); } }; img.onerror = (err) => { console.error('H5 图片加载失败:', err); reject(err); }; img.src = imagePath; } catch (error) { console.error('H5 创建图片对象失败:', error); reject(error); } }); // #endif // #ifndef H5 // App/小程序端水印实现(保持原有逻辑) return new Promise(async (resolve, reject) => { try { // 获取原图文件大小 const originalFileSize = await getFileSize(imagePath); console.log('原图文件大小:', originalFileSize.sizeKB, 'KB'); // 计算压缩质量 const compressionQuality = quality !== null ? quality : calculateQuality(originalFileSize.sizeKB); console.log('使用压缩质量:', compressionQuality); // 获取图片信息 uni.getImageInfo({ src: imagePath, success: (imageInfo) => { const { width, height } = imageInfo; console.log('原图尺寸:', width, 'x', height); // 计算输出尺寸 const outputSize = calculateOutputSize(width, height, maxWidth); console.log('输出尺寸:', outputSize.width, 'x', outputSize.height); // 创建canvas上下文 const canvas = uni.createCanvasContext('watermarkCanvas'); // 清空canvas canvas.clearRect(0, 0, outputSize.width, outputSize.height); // 绘制原图片到canvas canvas.drawImage(imagePath, 0, 0, outputSize.width, outputSize.height); // 处理水印文本,超过25个字符换行,最多3行 const processText = (text, maxChars = 25, maxLines = 3) => { if (text.length <= maxChars) { return [text]; } const lines = []; let currentLine = ''; let lineCount = 0; for (let i = 0; i < text.length && lineCount < maxLines; i++) { currentLine += text[i]; if (currentLine.length >= maxChars || i === text.length - 1) { lines.push(currentLine); lineCount++; currentLine = ''; // 如果还有剩余字符但已达到最大行数,添加省略号 if (lineCount === maxLines && i < text.length - 1) { lines[lines.length - 1] = lines[lines.length - 1].slice(0, -3) + '...'; break; } } } return lines; }; // 水印内容 const watermarkText = [ `时间: ${watermarkInfo.time}`, `经度: ${watermarkInfo.longitude}`, `维度: ${watermarkInfo.latitude}`, ]; var location = processText("位置: " + watermarkInfo.location); watermarkText.push(...location); var department = processText("部门: " + watermarkInfo.department); watermarkText.push(...department); var status = processText("状态: " + watermarkInfo.status); watermarkText.push(...status); var workers = processText("人员: " + watermarkInfo.workers.join(', ')); watermarkText.push(...workers); var remarks = processText("内容: " + watermarkInfo.remarks); watermarkText.push(...remarks); // 定义绘制文字水印的函数 const drawTextWatermark = () => { // 计算水印位置(左下角) const padding = 30; const fontSize = 40; const lineHeight = 50; const startX = padding; const startY = outputSize.height - padding - (watermarkText.length * lineHeight); // 设置文字样式 canvas.setFillStyle('rgba(255, 255, 255, 1)'); canvas.setFontSize(fontSize); canvas.setTextBaseline('top'); // 绘制文字 watermarkText.forEach((text, index) => { canvas.fillText(text, startX, startY + (index * lineHeight)); }); // 如果有logo,在文字水印上方绘制logo if (logoUrl) { // 使用缓存获取logo图片 getCachedLogo(logoUrl).then((cachedLogoPath) => { // 动态计算logo位置:在文字水印上方 const logoSize = 200; // logo大小 const logoPadding = 30; const logoX = logoPadding; // logo位置 = 文字水印起始位置 - logo高度 - 间距 const logoY = startY - logoSize - 10; // 设置logo透明度 canvas.setGlobalAlpha(logoOpacity); // 绘制logo canvas.drawImage(cachedLogoPath, logoX, logoY, logoSize, logoSize); // 恢复透明度为1(不影响后续绘制) canvas.setGlobalAlpha(1); // 绘制到canvas canvas.draw(true, () => { console.log('Canvas绘制完成(包含logo)'); // 延迟确保绘制完成 setTimeout(() => { // 将canvas导出为图片 uni.canvasToTempFilePath({ canvasId: 'watermarkCanvas', width: outputSize.width, height: outputSize.height, fileType: 'jpg', // 使用jpg格式,文件更小 quality: compressionQuality, // 使用动态计算的压缩质量 success: (res) => { console.log('导出成功:', res.tempFilePath); console.log('水印图片尺寸:', outputSize.width, 'x', outputSize.height); handleWatermarkExport(res.tempFilePath, originalFileSize, outputSize.width, outputSize.height, resolve); }, fail: (err) => { console.error('导出图片失败:', err); reject(err); } }); }, 100); }); }).catch((err) => { console.error('获取logo失败:', err); // logo获取失败时,只绘制文字水印 canvas.draw(true, () => { console.log('Canvas绘制完成(logo获取失败)'); // 延迟确保绘制完成 setTimeout(() => { // 将canvas导出为图片 uni.canvasToTempFilePath({ canvasId: 'watermarkCanvas', width: outputSize.width, height: outputSize.height, fileType: 'jpg', // 使用jpg格式,文件更小 quality: compressionQuality, // 使用动态计算的压缩质量 success: (res) => { console.log('导出成功:', res.tempFilePath); console.log('水印图片尺寸:', outputSize.width, 'x', outputSize.height); handleWatermarkExport(res.tempFilePath, originalFileSize, outputSize.width, outputSize.height, resolve); }, fail: (err) => { console.error('导出图片失败:', err); reject(err); } }); }, 100); }); }); } else { // 没有logo时,只绘制文字水印 canvas.draw(true, () => { console.log('Canvas绘制完成(无logo)'); // 延迟确保绘制完成 setTimeout(() => { // 将canvas导出为图片 uni.canvasToTempFilePath({ canvasId: 'watermarkCanvas', width: outputSize.width, height: outputSize.height, fileType: 'jpg', // 使用jpg格式,文件更小 quality: compressionQuality, // 使用动态计算的压缩质量 success: (res) => { console.log('导出成功:', res.tempFilePath); console.log('水印图片尺寸:', outputSize.width, 'x', outputSize.height); handleWatermarkExport(res.tempFilePath, originalFileSize, outputSize.width, outputSize.height, resolve); }, fail: (err) => { console.error('导出图片失败:', err); reject(err); } }); }, 100); }); } }; // 开始绘制文字水印 drawTextWatermark(); }, fail: (err) => { console.error('获取图片信息失败:', err); reject(err); } }); } catch (error) { console.error('处理图片失败:', error); reject(error); } }); // #endif } /** * 保存图片到相册(兼容 H5 / App / 小程序) * @param {string} image - 图片路径或 URL * @returns {Promise} 是否保存成功 */ export const saveImageToPhotosAlbum = (image) => { return new Promise((resolve, reject) => { // #ifdef H5 try { // 创建一个隐藏的 a 标签,触发下载 const link = document.createElement("a"); console.log("下载地址:"+image); link.href = image; // 如果 image 是 blob url 或 http url,都可以 link.download = "image_" + Date.now()+".jpg"; // 下载文件名 document.body.appendChild(link); link.click(); document.body.removeChild(link); console.log("H5 触发浏览器下载成功"); resolve(true); } catch (err) { console.error("H5 保存图片失败:", err); reject(err); } // #endif // #ifndef H5 uni.saveImageToPhotosAlbum({ filePath: image, success: () => { console.log("图片保存到相册成功"); resolve(true); }, fail: (err) => { console.error("保存到相册失败:", err); if (err.errMsg && err.errMsg.includes("auth deny")) { uni.showModal({ title: "提示", content: "需要您授权保存图片到相册,请在设置中开启相册权限", showCancel: false, confirmText: "知道了", }); } resolve(false); }, }); // #endif }); }; /** * 批量保存图片到相册(兼容 H5 / App / 小程序) * @param {string[]} images - 图片路径数组 * @param {function} onProgress - 进度回调 (completed, total) * @returns {Promise<{success: number, failed: number}>} 保存结果统计 */ export const saveImagesToPhotosAlbum = async (images, onProgress = null) => { const result = { success: 0, failed: 0 }; for (let i = 0; i < images.length; i++) { try { await saveImageToPhotosAlbum(images[i]); result.success++; } catch (err) { console.error(`保存第${i + 1}张图片失败:`, err); result.failed++; } if (onProgress) { onProgress(i + 1, images.length); } } return result; }; /** * 图片转Base64(兼容小程序、App、H5) * @param {string} filePath - 图片路径(小程序临时路径 / H5本地URL / App本地路径) * @returns {Promise} Base64字符串(带data:image/前缀) */ export const imageToBase64 = (filePath) => { return new Promise((resolve, reject) => { // #ifdef MP-WEIXIN // 微信小程序环境 uni.getImageInfo({ src: filePath, success: (info) => { const type = info.type || 'jpeg'; uni.getFileSystemManager().readFile({ filePath, encoding: 'base64', success: (res) => resolve(`data:image/${type};base64,${res.data}`), fail: reject }); }, fail: reject }); // #endif // #ifdef APP-PLUS // App 环境 plus.io.resolveLocalFileSystemURL(filePath, (entry) => { entry.file((file) => { const reader = new plus.io.FileReader(); reader.onloadend = (e) => { resolve(e.target.result); // 已经是 data:image/...;base64,... }; reader.readAsDataURL(file); }, reject); }, reject); // #endif // #ifdef H5 // H5 环境 const img = new Image(); img.crossOrigin = "anonymous"; // 先根据文件地址后缀判断类型 let mimeType = "image/jpeg"; // 默认 const match = filePath.match(/\.(png|jpe?g|gif|bmp|webp|svg)(\?.*)?$/i); if (match) { mimeType = `image/${match[1].toLowerCase()}`; // jpg -> image/jpeg if (mimeType === "image/jpg") mimeType = "image/jpeg"; } img.src = filePath; img.onload = () => { const canvas = document.createElement("canvas"); canvas.width = img.width; canvas.height = img.height; const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, img.width, img.height); const dataURL = canvas.toDataURL(mimeType, 1.0); resolve(dataURL); }; img.onerror = reject; // #endif }); };