ImageMagickCompressService.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <?php
  2. namespace app\common\service;
  3. use Exception;
  4. class ImageMagickCompressService
  5. {
  6. /**
  7. * 使用ImageMagick压缩图片
  8. */
  9. public static function compress($sourcePath, $compressConfig = [])
  10. {
  11. try {
  12. // 检查ImageMagick扩展
  13. if (!extension_loaded('imagick')) {
  14. outFileLog('ImageMagick扩展未安装', 'upload_img', 'imagick_not_installed');
  15. return false;
  16. }
  17. // 默认配置
  18. $config = array_merge([
  19. 'max_width' => 1920,
  20. 'max_height' => 1080,
  21. 'quality' => 80,
  22. 'format' => null // 保持原格式
  23. ], $compressConfig);
  24. // 检查源文件
  25. if (!file_exists($sourcePath)) {
  26. throw new Exception('源文件不存在: ' . $sourcePath);
  27. }
  28. // 获取文件信息
  29. $pathInfo = pathinfo($sourcePath);
  30. $extension = strtolower($pathInfo['extension']);
  31. // 支持的格式
  32. $supportedFormats = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
  33. if (!in_array($extension, $supportedFormats)) {
  34. outFileLog('不支持的图片格式: ' . $extension, 'upload_img', 'unsupported_format');
  35. return false;
  36. }
  37. // 创建Imagick对象
  38. $imagick = new \Imagick($sourcePath);
  39. // 获取原始尺寸
  40. $originalWidth = $imagick->getImageWidth();
  41. $originalHeight = $imagick->getImageHeight();
  42. outFileLog("原始尺寸: {$originalWidth}x{$originalHeight}", 'upload_img', 'original_size');
  43. // 计算新尺寸
  44. $newSize = self::calculateNewSize(
  45. $originalWidth,
  46. $originalHeight,
  47. $config['max_width'],
  48. $config['max_height']
  49. );
  50. // 如果需要缩放
  51. if ($newSize['width'] < $originalWidth || $newSize['height'] < $originalHeight) {
  52. $imagick->resizeImage(
  53. $newSize['width'],
  54. $newSize['height'],
  55. \Imagick::FILTER_LANCZOS,
  56. 1
  57. );
  58. outFileLog("压缩后尺寸: {$newSize['width']}x{$newSize['height']}", 'upload_img', 'compressed_size');
  59. }
  60. // 设置压缩质量
  61. $imagick->setImageCompressionQuality($config['quality']);
  62. // 去除EXIF信息减小文件大小
  63. $imagick->stripImage();
  64. // 生成压缩后的文件路径
  65. $compressedPath = self::generateCompressedPath($sourcePath);
  66. // 保存压缩后的图片
  67. $imagick->writeImage($compressedPath);
  68. $imagick->clear();
  69. $imagick->destroy();
  70. // 检查压缩效果
  71. $originalSize = filesize($sourcePath);
  72. $compressedSize = filesize($compressedPath);
  73. $compressionRatio = round((1 - $compressedSize / $originalSize) * 100, 2);
  74. outFileLog("压缩完成,原大小: {$originalSize}字节,压缩后: {$compressedSize}字节,压缩率: {$compressionRatio}%", 'upload_img', 'compression_result');
  75. return $compressedPath;
  76. } catch (Exception $e) {
  77. outFileLog('ImageMagick压缩失败: ' . $e->getMessage(), 'upload_img', 'imagick_compress_error');
  78. return false;
  79. }
  80. }
  81. /**
  82. * 计算新尺寸(保持宽高比)
  83. */
  84. private static function calculateNewSize($width, $height, $maxWidth, $maxHeight)
  85. {
  86. $ratio = min($maxWidth / $width, $maxHeight / $height, 1);
  87. return [
  88. 'width' => intval($width * $ratio),
  89. 'height' => intval($height * $ratio)
  90. ];
  91. }
  92. /**
  93. * 生成压缩后的文件路径
  94. */
  95. private static function generateCompressedPath($sourcePath)
  96. {
  97. $pathInfo = pathinfo($sourcePath);
  98. return $pathInfo['dirname'] . '/' . $pathInfo['filename'] . '_compressed.' . $pathInfo['extension'];
  99. }
  100. }