86 lines
2.2 KiB
TypeScript
86 lines
2.2 KiB
TypeScript
import sharp from 'sharp'
|
||
|
||
interface ProcessImageOptions {
|
||
maxSizeKB?: number // 最大文件大小(KB)
|
||
maxWidth?: number // 最大宽度(像素)
|
||
format?: 'webp' | 'jpeg' | 'png'
|
||
}
|
||
|
||
/**
|
||
* 处理图片:压缩、调整尺寸、转换格式
|
||
* @param buffer 原始图片buffer
|
||
* @param options 处理选项
|
||
* @returns 处理后的图片buffer
|
||
*/
|
||
export async function processImage(
|
||
buffer: Buffer,
|
||
options: ProcessImageOptions = {}
|
||
): Promise<Buffer> {
|
||
const {
|
||
maxSizeKB = 300, // 默认300KB
|
||
maxWidth = 600, // 默认600像素
|
||
format = 'webp', // 默认webP格式
|
||
} = options
|
||
|
||
try {
|
||
// 获取原始图片信息
|
||
const image = sharp(buffer)
|
||
const metadata = await image.metadata()
|
||
|
||
// 计算新尺寸(保持比例)
|
||
let width = metadata.width || maxWidth
|
||
let height = metadata.height
|
||
|
||
if (width > maxWidth) {
|
||
const ratio = maxWidth / width
|
||
width = maxWidth
|
||
if (height) {
|
||
height = Math.round(height * ratio)
|
||
}
|
||
}
|
||
|
||
// 初始质量
|
||
let quality = 80
|
||
|
||
let processedBuffer: Buffer
|
||
|
||
// 第一次处理
|
||
processedBuffer = await image
|
||
.resize(width, height, {
|
||
fit: 'inside',
|
||
withoutEnlargement: true,
|
||
})
|
||
.webp({ quality })
|
||
.toBuffer()
|
||
|
||
// 如果文件还是太大,逐步降低质量
|
||
const maxBytes = maxSizeKB * 1024
|
||
while (processedBuffer.length > maxBytes && quality > 20) {
|
||
quality -= 10
|
||
processedBuffer = await sharp(buffer)
|
||
.resize(width, height, {
|
||
fit: 'inside',
|
||
withoutEnlargement: true,
|
||
})
|
||
.webp({ quality })
|
||
.toBuffer()
|
||
}
|
||
|
||
console.log(`图片处理完成: ${metadata.width}x${metadata.height} -> ${width}x${height}, ${(buffer.length / 1024).toFixed(2)}KB -> ${(processedBuffer.length / 1024).toFixed(2)}KB, 质量: ${quality}`)
|
||
|
||
return processedBuffer
|
||
} catch (error) {
|
||
console.error('图片处理失败:', error)
|
||
throw new Error('图片处理失败')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取处理后的文件名(添加.webp扩展名)
|
||
*/
|
||
export function getProcessedFileName(originalName: string): string {
|
||
const nameWithoutExt = originalName.replace(/\.[^/.]+$/, '')
|
||
return `${nameWithoutExt}.webp`
|
||
}
|
||
|