imageCompressor.ts 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import sharp from 'sharp';
  2. import fs from 'fs';
  3. /**
  4. * 压缩图片到目标大小左右
  5. * @param inputPath 输入文件路径
  6. * @param outputPath 输出文件路径
  7. * @param targetSize 目标大小(字节),默认100KB
  8. */
  9. export async function compressImage(
  10. inputPath: string,
  11. outputPath: string,
  12. targetSize: number = 100 * 1024
  13. ): Promise<{ success: boolean; finalSize?: number; error?: string }> {
  14. try {
  15. let quality = 80;
  16. let compressedSize = targetSize + 1;
  17. // 获取图片信息
  18. const metadata = await sharp(inputPath).metadata();
  19. let width = metadata.width;
  20. let height = metadata.height;
  21. // 如果图片尺寸较大,先调整尺寸
  22. if (width && height && (width > 2000 || height > 2000)) {
  23. width = Math.round(width * 0.5);
  24. height = Math.round(height * 0.5);
  25. }
  26. while (compressedSize > targetSize && quality > 10) {
  27. await sharp(inputPath)
  28. .resize(width, height, {
  29. fit: 'inside',
  30. withoutEnlargement: true,
  31. })
  32. .jpeg({
  33. quality: quality,
  34. mozjpeg: true,
  35. })
  36. .toFile(outputPath);
  37. // 获取压缩后文件大小
  38. const stats = fs.statSync(outputPath);
  39. compressedSize = stats.size;
  40. // 如果仍然大于目标大小,降低质量继续压缩
  41. if (compressedSize > targetSize) {
  42. quality -= 15;
  43. if (quality < 10) quality = 10;
  44. }
  45. }
  46. return { success: true, finalSize: compressedSize };
  47. } catch (error) {
  48. return {
  49. success: false,
  50. error: error instanceof Error ? error.message : '压缩失败',
  51. };
  52. }
  53. }