Files
2025-10-05 14:03:21 +08:00

250 lines
6.7 KiB
TypeScript
Executable File

// 图片处理工具类 - 实现图片压缩和选择功能
interface ImageCompressOptions {
quality?: number; // 图片质量 0-100
maxWidth?: number; // 最大宽度
maxHeight?: number; // 最大高度
}
interface ImageSelectOptions {
sourceType?: ('album' | 'camera')[]; // 图片来源
sizeType?: ('original' | 'compressed')[]; // 图片尺寸
count?: number; // 选择数量
compress?: ImageCompressOptions; // 压缩选项
}
class ImageManager {
// 选择图片
selectImage(options: ImageSelectOptions = {}): Promise<string> {
const {
sourceType = ['album', 'camera'],
sizeType = ['compressed'],
count = 1,
compress
} = options
return new Promise((resolve, reject) => {
wx.chooseMedia({
count,
mediaType: ['image'],
sourceType,
sizeType,
success: async (res) => {
try {
const tempFilePath = res.tempFiles[0].tempFilePath
// 如果需要压缩
if (compress) {
const compressedPath = await this.compressImage(tempFilePath, compress)
resolve(compressedPath)
} else {
resolve(tempFilePath)
}
} catch (error) {
console.error('图片处理失败:', error)
reject(error)
}
},
fail: (error) => {
if (error.errMsg.includes('cancel')) {
reject(new Error('用户取消选择'))
} else {
wx.showToast({
title: '选择图片失败',
icon: 'none'
})
reject(error)
}
}
})
})
}
// 拍照
takePhoto(options: ImageCompressOptions = {}): Promise<string> {
return this.selectImage({
sourceType: ['camera'],
compress: options
})
}
// 从相册选择
chooseFromAlbum(options: ImageCompressOptions = {}): Promise<string> {
return this.selectImage({
sourceType: ['album'],
compress: options
})
}
// 压缩图片
compressImage(filePath: string, options: ImageCompressOptions = {}): Promise<string> {
const {
quality = 80,
maxWidth = 1920,
maxHeight = 1920
} = options
return new Promise((resolve, reject) => {
// 首先获取图片信息
wx.getImageInfo({
src: filePath,
success: (info) => {
const { width, height } = info
// 计算压缩后的尺寸
let targetWidth = width
let targetHeight = height
if (width > maxWidth || height > maxHeight) {
const ratio = Math.min(maxWidth / width, maxHeight / height)
targetWidth = Math.floor(width * ratio)
targetHeight = Math.floor(height * ratio)
}
// 使用 Canvas 压缩图片
this.compressWithCanvas(filePath, targetWidth, targetHeight, quality)
.then(resolve)
.catch(reject)
},
fail: reject
})
})
}
// 使用 Canvas 压缩图片
private compressWithCanvas(
imagePath: string,
targetWidth: number,
targetHeight: number,
quality: number
): Promise<string> {
return new Promise((resolve, reject) => {
// 使用微信小程序的图片压缩 API
wx.compressImage({
src: imagePath,
quality: quality,
success: (res) => {
console.log('图片压缩成功:', {
原图片: imagePath,
压缩后: res.tempFilePath,
质量: quality
})
resolve(res.tempFilePath)
},
fail: (error) => {
console.error('图片压缩失败:', error)
// 如果压缩失败,返回原图片
resolve(imagePath)
}
})
})
}
// 获取图片信息
getImageInfo(filePath: string): Promise<any> {
return new Promise((resolve, reject) => {
wx.getImageInfo({
src: filePath,
success: resolve,
fail: reject
})
})
}
// 预览图片
previewImage(urls: string[], current?: string) {
wx.previewImage({
urls,
current: current || urls[0]
})
}
// 保存图片到相册
saveImageToPhotosAlbum(filePath: string): Promise<void> {
return new Promise((resolve, reject) => {
// 检查权限
wx.getSetting({
success: (res) => {
if (res.authSetting['scope.writePhotosAlbum']) {
// 已授权,直接保存
this.doSaveImage(filePath).then(resolve).catch(reject)
} else {
// 请求授权
wx.authorize({
scope: 'scope.writePhotosAlbum',
success: () => {
this.doSaveImage(filePath).then(resolve).catch(reject)
},
fail: () => {
wx.showModal({
title: '权限申请',
content: '需要相册权限来保存图片,请在设置中开启',
success: (modalRes) => {
if (modalRes.confirm) {
wx.openSetting()
}
}
})
reject(new Error('用户拒绝授权'))
}
})
}
},
fail: reject
})
})
}
// 执行保存图片
private doSaveImage(filePath: string): Promise<void> {
return new Promise((resolve, reject) => {
wx.saveImageToPhotosAlbum({
filePath,
success: () => {
wx.showToast({
title: '保存成功',
icon: 'success'
})
resolve()
},
fail: (error) => {
wx.showToast({
title: '保存失败',
icon: 'none'
})
reject(error)
}
})
})
}
// 计算图片显示尺寸(保持宽高比)
calculateDisplaySize(
originalWidth: number,
originalHeight: number,
maxWidth: number,
maxHeight: number
): { width: number; height: number } {
const ratio = Math.min(maxWidth / originalWidth, maxHeight / originalHeight)
return {
width: Math.floor(originalWidth * ratio),
height: Math.floor(originalHeight * ratio)
}
}
// 生成缩略图
generateThumbnail(filePath: string, size: number = 200): Promise<string> {
return this.compressImage(filePath, {
quality: 70,
maxWidth: size,
maxHeight: size
})
}
}
// 导出单例
const imageManager = new ImageManager()
export default imageManager
export { ImageManager }