250 lines
6.7 KiB
TypeScript
Executable File
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 } |