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 { 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` }