198 lines
6.9 KiB
JavaScript
198 lines
6.9 KiB
JavaScript
// 图片处理工具类
|
||
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
|