bonus-material-app/src/services/utils/imageUtils.js

198 lines
6.9 KiB
JavaScript
Raw Normal View History

2025-07-30 14:35:01 +08:00
// 图片处理工具类
class ImageUtils {
/**
* 将图片转换为Base64字符串相当于Android的bitmapToString
* @param {string} imagePath 图片路径
* @param {number} quality 压缩质量 0-100
* @returns {Promise<string>} Base64字符串
*/
static async imageToBase64(imagePath, quality = 50) {
try {
// 如果已经是base64格式直接返回数据部分
if (imagePath.startsWith("data:image/")) {
return imagePath.split(",")[1]
}
// 如果是纯base64字符串直接返回
if (!imagePath.includes("/") && !imagePath.includes("\\")) {
return imagePath
}
// 压缩图片
const compressResult = await new Promise((resolve, reject) => {
window.uni.compressImage({
src: imagePath,
quality: quality,
success: resolve,
fail: reject,
})
})
// 读取压缩后的文件并转换为base64
const fileManager = window.uni.getFileSystemManager()
const base64Data = await new Promise((resolve, reject) => {
fileManager.readFile({
filePath: compressResult.tempFilePath,
encoding: "base64",
success: (res) => resolve(res.data),
fail: reject,
})
})
return base64Data
} catch (error) {
console.error("Image to base64 conversion failed:", error)
throw error
}
}
/**
* 获取缩放后的图片相当于Android的getSmallBitmap
* @param {string} imagePath 图片路径
* @param {number} maxWidth 最大宽度
* @param {number} maxHeight 最大高度
* @returns {Promise<string>} 处理后的图片路径
*/
static async getSmallImage(imagePath, maxWidth = 1024, maxHeight = 1024) {
try {
return await this.resizeImageWithCanvas(imagePath, maxWidth, maxHeight)
} catch (error) {
console.error("Get small image failed:", error)
// 如果canvas方法失败尝试使用压缩API
return await this.fallbackCompress(imagePath, maxWidth, maxHeight)
}
}
/**
* 使用Canvas调整图片尺寸
* @param {string} imagePath 图片路径
* @param {number} maxWidth 最大宽度
* @param {number} maxHeight 最大高度
* @returns {Promise<string>} 处理后的图片路径
*/
static async resizeImageWithCanvas(imagePath, maxWidth, maxHeight) {
return new Promise((resolve, reject) => {
// 获取图片信息
window.uni.getImageInfo({
src: imagePath,
success: (imageInfo) => {
const { width, height } = imageInfo
// 计算缩放比例
const scale = this.calculateScale(width, height, maxWidth, maxHeight)
const newWidth = Math.floor(width * scale)
const newHeight = Math.floor(height * scale)
// 如果不需要缩放,直接返回原图
if (scale >= 1) {
resolve(imagePath)
return
}
// 创建canvas上下文
const canvasId = "imageProcessCanvas_" + Date.now()
const ctx = window.uni.createCanvasContext(canvasId)
// 绘制缩放后的图片
ctx.drawImage(imagePath, 0, 0, newWidth, newHeight)
ctx.draw(false, () => {
// 导出canvas为临时文件
window.uni.canvasToTempFilePath({
canvasId: canvasId,
fileType: "jpg",
quality: 0.8,
success: (res) => {
resolve(res.tempFilePath)
},
fail: reject,
})
})
},
fail: reject,
})
})
}
/**
* 备用压缩方法
* @param {string} imagePath 图片路径
* @param {number} maxWidth 最大宽度
* @param {number} maxHeight 最大高度
* @returns {Promise<string>} 处理后的图片路径
*/
static async fallbackCompress(imagePath, maxWidth, maxHeight) {
return new Promise((resolve, reject) => {
window.uni.compressImage({
src: imagePath,
quality: 80,
compressedWidth: maxWidth,
compressedHeight: maxHeight,
success: (res) => resolve(res.tempFilePath),
fail: reject,
})
})
}
/**
* 计算缩放比例相当于Android的calculateInSampleSize
* @param {number} originalWidth 原始宽度
* @param {number} originalHeight 原始高度
* @param {number} maxWidth 最大宽度
* @param {number} maxHeight 最大高度
* @returns {number} 缩放比例
*/
static calculateScale(originalWidth, originalHeight, maxWidth, maxHeight) {
if (originalWidth <= maxWidth && originalHeight <= maxHeight) {
return 1 // 不需要缩放
}
const widthScale = maxWidth / originalWidth
const heightScale = maxHeight / originalHeight
// 选择较小的缩放比例,确保图片完全适应限制尺寸
return Math.min(widthScale, heightScale)
}
/**
* 批量处理图片
* @param {string} imagePath 图片路径
* @param {object} options 处理选项
* @returns {Promise<string>} 处理后的Base64字符串
*/
static async processImage(imagePath, options = {}) {
const { maxWidth = 1024, maxHeight = 1024, quality = 50, outputFormat = "base64" } = options
try {
// 1. 先缩放图片
const resizedImagePath = await this.getSmallImage(imagePath, maxWidth, maxHeight)
// 2. 根据输出格式返回结果
if (outputFormat === "base64") {
return await this.imageToBase64(resizedImagePath, quality)
} else {
return resizedImagePath
}
} catch (error) {
console.error("Process image failed:", error)
throw error
}
}
/**
* 获取图片尺寸信息
* @param {string} imagePath 图片路径
* @returns {Promise<object>} 图片信息
*/
static async getImageInfo(imagePath) {
return new Promise((resolve, reject) => {
window.uni.getImageInfo({
src: imagePath,
success: resolve,
fail: reject,
})
})
}
}
export default ImageUtils