Files
i-love/app/Service/ImageService.php
2025-06-17 14:59:07 +08:00

190 lines
5.9 KiB
PHP

<?php
namespace App\Service;
use App\Models\ImagesModel;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class ImageService
{
/**
* 处理上传的图片
*
* @param UploadedFile $imageFile
* @return array 包含三个路径的数组
*/
public function processImage($imageFile, $pid = 1)
{
// 1. 保存原始图片
$originalPath = $this->storeOriginalImage($imageFile);
// 2. 无损压缩图片
$compressedPath = $this->compressToWebp($originalPath);
// 3. 添加水印
$watermarkedPath = $this->addWatermark($compressedPath);
ImagesModel::create([
'photo_album_id' => $pid,
'title' => date('Y-m-d H:i:s'),
'original' => $originalPath,
'compressed' => $compressedPath,
'watermarked' => $watermarkedPath,
'created_at' => time()
]);
return [
'original' => $originalPath,
'compressed' => $compressedPath,
'watermarked' => $watermarkedPath
];
}
/**
* 保存原始图片
*/
protected function storeOriginalImage($imageFile)
{
dd($imageFile);
$path = 'images/original/' . Str::random(40) . '.' . $imageFile->getClientOriginalExtension();
Storage::put($path, file_get_contents($imageFile));
return $path;
}
/**
* 使用WebP格式高效压缩图片
*
* @param string $originalPath 原始图片路径
* @param int $quality WebP压缩质量(1-100)
* @param int|null $maxWidth 最大宽度(可选)
* @param int|null $maxHeight 最大高度(可选)
* @return string 压缩后的图片路径
*/
protected function compressToWebp($originalPath, $quality = 85, $maxWidth = null, $maxHeight = null)
{
// 获取原始图片内容
$imageContent = Storage::get($originalPath);
$image = imagecreatefromstring($imageContent);
// 获取图片信息
$info = getimagesizefromstring($imageContent);
$width = $info[0];
$height = $info[1];
$mime = $info['mime'];
// 调整图片尺寸(如果指定了最大宽高)
if ($maxWidth || $maxHeight) {
// 计算新尺寸,保持宽高比
$originalRatio = $width / $height;
// 如果只指定了一个维度,自动计算另一个
if (!$maxWidth) {
$maxWidth = (int)($maxHeight * $originalRatio);
} elseif (!$maxHeight) {
$maxHeight = (int)($maxWidth / $originalRatio);
}
// 计算最终尺寸(不超过原始尺寸)
$newWidth = min($width, $maxWidth);
$newHeight = min($height, $maxHeight);
// 创建新尺寸的画布
$resizedImage = imagecreatetruecolor($newWidth, $newHeight);
// 保留透明度 (PNG/GIF)
if ($mime == 'image/png' || $mime == 'image/gif') {
imagealphablending($resizedImage, false);
imagesavealpha($resizedImage, true);
$transparent = imagecolorallocatealpha($resizedImage, 255, 255, 255, 127);
imagefilledrectangle($resizedImage, 0, 0, $newWidth, $newHeight, $transparent);
}
// 调整图片大小
imagecopyresampled($resizedImage, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
// 替换原始图片资源
imagedestroy($image);
$image = $resizedImage;
$width = $newWidth;
$height = $newHeight;
}
// 生成压缩后的WebP图片
$compressedPath = 'images/compressed/' . Str::random(40) . '.webp';
// 保存WebP图片
ob_start();
imagewebp($image, null, $quality);
$compressedContent = ob_get_clean();
Storage::put($compressedPath, $compressedContent);
// 释放内存
imagedestroy($image);
return $compressedPath;
}
/**
* 添加水印
*/
protected function addWatermark($imagePath)
{
$imageContent = Storage::get($imagePath);
$image = imagecreatefromstring($imageContent);
// 获取图片信息
$info = getimagesizefromstring($imageContent);
$width = $info[0];
$height = $info[1];
$mime = $info['mime'];
// 水印文字设置
$text = '@ Li Qi';
$fontSize = 20;
$fontFile = public_path('fonts/arial.ttf'); // 确保字体文件存在
// $fontFile = ''; // 确保字体文件存在
$textColor = imagecolorallocatealpha($image, 255, 255, 255, 50);
// 计算文字位置 (右下角)
$textBox = imagettfbbox($fontSize, 0, $fontFile, $text);
$textWidth = $textBox[2] - $textBox[0];
$textHeight = $textBox[7] - $textBox[1];
$x = $width - $textWidth - 40;
$y = $height - $textHeight - 40;
// 添加文字水印
imagettftext($image, $fontSize, 0, $x, $y, $textColor, $fontFile, $text);
// 生成带水印的路径
$extension = pathinfo($imagePath, PATHINFO_EXTENSION);
$watermarkedPath = 'images/watermarked/' . Str::random(40) . '.' . $extension;
// 保存带水印的图片
ob_start();
switch ($mime) {
case 'image/jpeg':
imagejpeg($image, null, 100);
break;
case 'image/png':
imagepng($image, null, 9);
break;
case 'image/gif':
imagegif($image);
break;
case 'image/webp':
imagewebp($image, null, 100);
break;
}
$watermarkedContent = ob_get_clean();
Storage::put($watermarkedPath, $watermarkedContent);
// 释放内存
imagedestroy($image);
return $watermarkedPath;
}
}