WorkCamera/uniapp/WorkCameraf/common/utils.js
2026-01-04 22:42:52 +08:00

983 lines
28 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 获取位置的异步函数
* 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<object>} - 返回选择的图片信息
*/
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<string>} - 返回本地缓存路径
*/
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<object>} - 返回包含水印图片路径和文件大小信息的对象
*/
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<boolean>} 是否保存成功
*/
export const saveImageToPhotosAlbum = (image) => {
return new Promise((resolve, reject) => {
// #ifdef H5
try {
// 创建一个隐藏的 a 标签,触发下载
const link = document.createElement("a");
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
});
};
/**
* 图片转Base64兼容小程序、App、H5
* @param {string} filePath - 图片路径(小程序临时路径 / H5本地URL / App本地路径
* @returns {Promise<string>} 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
});
};