| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- <?php
- namespace app\common\service;
- use Exception;
- class ImageCompressService
- {
- /**
- * 压缩图片
- * @param string $sourcePath 源文件路径
- * @param int $quality 压缩质量 (1-100)
- * @param int $maxWidth 最大宽度
- * @param int $maxHeight 最大高度
- * @return string|false 压缩后的文件路径
- */
- public static function compress($sourcePath, $quality = 80, $maxWidth = 1920, $maxHeight = 1080)
- {
- try {
- // 验证输入参数
- if (empty($sourcePath)) {
- throw new Exception('源文件路径不能为空');
- }
- outFileLog($sourcePath,'upload_img','$sourcePath1');
- // 获取图片信息
- $imageInfo = getimagesize($sourcePath);
- outFileLog($imageInfo,'upload_img','imgInfo');
- if (!$imageInfo) {
- throw new Exception('无法获取图片信息');
- }
- $width = $imageInfo[0];
- $height = $imageInfo[1];
- $type = $imageInfo[2];
- outFileLog($width,'upload_img','$width');
- outFileLog($height,'upload_img','$height');
- // 如果图片尺寸已经很小,且质量要求不高,直接返回原文件
- if ($width <= $maxWidth && $height <= $maxHeight && $quality >= 90) {
- return $sourcePath;
- }
- outFileLog($sourcePath,'upload_img','$sourcePath2');
- // 计算新尺寸
- $newSize = self::calculateNewSize($width, $height, $maxWidth, $maxHeight);
- $newWidth = $newSize['width'];
- $newHeight = $newSize['height'];
- outFileLog($newWidth,'upload_img','$newWidth');
- outFileLog($newHeight,'upload_img','$newHeight');
- // 创建源图片资源
- $sourceImage = self::createImageFromType($sourcePath, $type);
- if (!$sourceImage) {
- throw new Exception('不支持的图片格式');
- }
- outFileLog($sourceImage,'upload_img','$sourceImage');
- // 创建新图片资源
- $newImage = imagecreatetruecolor($newWidth, $newHeight);
- outFileLog($newImage,'upload_img','$newImage');
- // 处理透明背景(PNG/GIF)
- if ($type == IMAGETYPE_PNG || $type == IMAGETYPE_GIF) {
- imagealphablending($newImage, false);
- imagesavealpha($newImage, true);
- $transparent = imagecolorallocatealpha($newImage, 255, 255, 255, 127);
- imagefill($newImage, 0, 0, $transparent);
- }
- // 重新采样
- imagecopyresampled($newImage, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
- // 生成压缩后的文件路径
- $compressedPath = self::generateCompressedPath($sourcePath);
- outFileLog($compressedPath,'upload_img','$compressedPath');
- // 保存压缩后的图片
- $result = self::saveImageByType($newImage, $compressedPath, $type, $quality);
- utFileLog($result,'upload_img','$result');
- // $imageInfo = getimagesize($result);
- // 释放内存
- imagedestroy($sourceImage);
- imagedestroy($newImage);
- return $result ? $compressedPath : false;
- } catch (Exception $e) {
- return false;
- }
- }
- /**
- * 计算新尺寸(保持宽高比)
- */
- private static function calculateNewSize($width, $height, $maxWidth, $maxHeight)
- {
- $ratio = min($maxWidth / $width, $maxHeight / $height, 1);
- return [
- 'width' => intval($width * $ratio),
- 'height' => intval($height * $ratio)
- ];
- }
- /**
- * 根据图片类型创建图片资源
- */
- private static function createImageFromType($path, $type)
- {
- // 检查文件是否存在
- if (!file_exists($path)) {
- throw new Exception('图片文件不存在: ' . $path);
- }
- outFileLog(file_exists($path),'upload_img','createImageFromType-$path1');
- // 检查文件是否可读
- if (!is_readable($path)) {
- throw new Exception('图片文件无法读取: ' . $path);
- }
- outFileLog(is_readable($path),'upload_img','createImageFromType-$path2');
- // 检查GD扩展
- if (!extension_loaded('gd')) {
- throw new Exception('GD扩展未安装');
- }
- outFileLog(extension_loaded('gd'),'upload_img','createImageFromType-gd');
- outFileLog($type,'upload_img','createImageFromType-$type');
- outFileLog($path,'upload_img','createImageFromType-$path');
- try {
- switch ($type) {
- case IMAGETYPE_JPEG:
- // PNG特殊处理
- outFileLog('开始处理PNG图片: ' . $path, 'upload_img', 'png_process_start');
- // 检查文件大小
- $fileSize = filesize($path);
- outFileLog('PNG文件大小: ' . $fileSize . ' bytes', 'upload_img', 'png_file_size');
- // 检查内存限制
- $memoryLimit = ini_get('memory_limit');
- $currentMemory = memory_get_usage(true);
- outFileLog('内存限制: ' . $memoryLimit . ', 当前使用: ' . $currentMemory, 'upload_img', 'memory_info');
- $image = imagecreatefromjpeg($path);
- outFileLog($image, 'upload_img', '$image112');
- if ($image === false) {
- // 获取详细错误信息
- $error = error_get_last();
- outFileLog('PNG创建失败,错误信息: ' . json_encode($error), 'upload_img', 'png_create_error');
- // 尝试使用getimagesize验证
- $imageInfo = @getimagesize($path);
- if ($imageInfo === false) {
- throw new Exception('PNG文件无法被识别,可能已损坏');
- }
- outFileLog('PNG图片信息: ' . json_encode($imageInfo), 'upload_img', 'png_image_info');
- }
- break;
- case IMAGETYPE_PNG:
- // PNG特殊处理
- outFileLog('开始处理PNG图片: ' . $path, 'upload_img', 'png_process_start');
- // 检查文件大小
- $fileSize = filesize($path);
- outFileLog('PNG文件大小: ' . $fileSize . ' bytes', 'upload_img', 'png_file_size');
- // 检查内存限制
- $memoryLimit = ini_get('memory_limit');
- $currentMemory = memory_get_usage(true);
- outFileLog('内存限制: ' . $memoryLimit . ', 当前使用: ' . $currentMemory, 'upload_img', 'memory_info');
- // 尝试创建PNG图片资源
- $image = @imagecreatefrompng($path);
- // $image = imagecreatefrompng($path);
- if ($image === false) {
- // 获取详细错误信息
- $error = error_get_last();
- outFileLog('PNG创建失败,错误信息: ' . json_encode($error), 'upload_img', 'png_create_error');
- // 尝试验证PNG文件头
- $handle = fopen($path, 'rb');
- $header = fread($handle, 8);
- fclose($handle);
- $pngSignature = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
- if ($header !== $pngSignature) {
- throw new Exception('PNG文件头不正确,文件可能损坏');
- }
- // 尝试使用getimagesize验证
- $imageInfo = @getimagesize($path);
- if ($imageInfo === false) {
- throw new Exception('PNG文件无法被识别,可能已损坏');
- }
- outFileLog('PNG图片信息: ' . json_encode($imageInfo), 'upload_img', 'png_image_info');
- }
- break;
- case IMAGETYPE_GIF:
- $image = imagecreatefromgif($path);
- break;
- case IMAGETYPE_WEBP:
- if (!function_exists('imagecreatefromwebp')) {
- throw new Exception('WebP格式不支持');
- }
- $image = imagecreatefromwebp($path);
- break;
- default:
- throw new Exception('不支持的图片格式: ' . $type);
- }
- if (!$image) {
- throw new Exception('创建图片资源失败,可能是内存不足或文件损坏');
- }
- outFileLog($image ? 'success' : 'failed', 'upload_img', 'createImageFromType-result');
- return $image;
- } catch (Exception $e) {
- outFileLog('图片处理异常: ' . $e->getMessage(), 'upload_img', 'createImageFromType-exception');
- throw new Exception('图片处理失败: ' . $e->getMessage());
- }
- }
- /**
- * 根据图片类型保存图片
- */
- private static function saveImageByType($image, $path, $type, $quality)
- {
- switch ($type) {
- case IMAGETYPE_JPEG:
- return imagejpeg($image, $path, $quality);
- case IMAGETYPE_PNG:
- // PNG压缩级别 0-9,质量参数需要转换
- $pngQuality = intval((100 - $quality) / 10);
- return imagepng($image, $path, $pngQuality);
- case IMAGETYPE_GIF:
- return imagegif($image, $path);
- case IMAGETYPE_WEBP:
- return imagewebp($image, $path, $quality);
- default:
- return false;
- }
- }
- /**
- * 生成压缩后的文件路径
- */
- private static function generateCompressedPath($originalPath)
- {
- $pathInfo = pathinfo($originalPath);
- return $pathInfo['dirname'] . '/' . $pathInfo['filename'] . '_compressed.' . $pathInfo['extension'];
- }
- }
|