提交
This commit is contained in:
186
app/service/CompressImgService.php
Normal file
186
app/service/CompressImgService.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace app\service;
|
||||
/**
|
||||
* 压缩二进制流图片
|
||||
*/
|
||||
class CompressImgService
|
||||
{
|
||||
/**
|
||||
* 压缩通过表单上传的图片
|
||||
*
|
||||
* @param string $fileData 图片的二进制数据
|
||||
* @param int $quality 压缩质量(0-100,仅适用于JPEG和WebP)
|
||||
* @param string|null $targetFormat 目标格式('jpeg', 'png', 'webp',默认使用原格式)
|
||||
* @return array 包含压缩后图片信息的数组
|
||||
*/
|
||||
function compress($fileData, $quality = 80, $targetFormat = null)
|
||||
{
|
||||
|
||||
// 读取上传的二进制数据
|
||||
$imageData = file_get_contents($fileData);
|
||||
if ($imageData === false) {
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => '无法读取上传的文件',
|
||||
];
|
||||
}
|
||||
|
||||
// 获取图片信息
|
||||
$imageInfo = getimagesizefromstring($imageData);
|
||||
if (!$imageInfo) {
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => '无法解析图片信息',
|
||||
];
|
||||
}
|
||||
|
||||
// 确定原始和目标格式
|
||||
$originalMimeType = $imageInfo['mime'];
|
||||
$originalExtension = image_type_to_extension($imageInfo[2], false);
|
||||
|
||||
if ($targetFormat === null) {
|
||||
$targetFormat = $originalExtension;
|
||||
}
|
||||
|
||||
// 创建图片资源
|
||||
switch (strtolower($originalExtension)) {
|
||||
case 'jpeg':
|
||||
case 'jpg':
|
||||
$image = imagecreatefromstring($imageData);
|
||||
break;
|
||||
case 'png':
|
||||
$image = imagecreatefromstring($imageData);
|
||||
break;
|
||||
case 'webp':
|
||||
$image = imagecreatefromstring($imageData);
|
||||
break;
|
||||
default:
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => '不支持的图片格式',
|
||||
];
|
||||
}
|
||||
|
||||
if (!$image) {
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => '无法创建图片资源',
|
||||
];
|
||||
}
|
||||
|
||||
// 压缩并转换图片
|
||||
ob_start();
|
||||
switch (strtolower($targetFormat)) {
|
||||
case 'jpeg':
|
||||
case 'jpg':
|
||||
imagejpeg($image, null, $quality);
|
||||
$compressedMimeType = 'image/jpeg';
|
||||
break;
|
||||
case 'png':
|
||||
$pngQuality = 9 - floor($quality / 11);
|
||||
imagepng($image, null, $pngQuality);
|
||||
$compressedMimeType = 'image/png';
|
||||
break;
|
||||
case 'webp':
|
||||
if (function_exists('imagewebp')) {
|
||||
imagewebp($image, null, $quality);
|
||||
$compressedMimeType = 'image/webp';
|
||||
} else {
|
||||
imagejpeg($image, null, $quality);
|
||||
$compressedMimeType = 'image/jpeg';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
imagedestroy($image);
|
||||
ob_end_clean();
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => "不支持的目标格式: {$targetFormat}",
|
||||
];
|
||||
}
|
||||
|
||||
$compressedData = ob_get_clean();
|
||||
imagedestroy($image);
|
||||
// 返回结果
|
||||
return [
|
||||
'code' => 1,
|
||||
'compressed_data' => $compressedData,
|
||||
'base64' => 'data:' . $compressedMimeType . ';base64,' . base64_encode($compressedData),
|
||||
];
|
||||
}
|
||||
|
||||
public function compressImage($filePath, $fileSize)
|
||||
{
|
||||
// 获取图片信息
|
||||
$imageInfo = getimagesize($filePath);
|
||||
if (!$imageInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$mime = $imageInfo['mime'];
|
||||
|
||||
// 根据MIME类型创建图像资源
|
||||
switch ($mime) {
|
||||
case 'image/jpeg':
|
||||
$image = imagecreatefromjpeg($filePath);
|
||||
break;
|
||||
case 'image/png':
|
||||
$image = imagecreatefrompng($filePath);
|
||||
break;
|
||||
case 'image/gif':
|
||||
$image = imagecreatefromgif($filePath);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$image) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 计算压缩质量(根据文件大小动态调整)
|
||||
$originalQuality = 85; // 初始质量
|
||||
$targetSize = 2.5 * 1024 * 1024; // 目标大小2.5MB
|
||||
|
||||
// 如果文件很大,降低初始质量
|
||||
if ($fileSize > 5 * 1024 * 1024) {
|
||||
$quality = 75;
|
||||
} elseif ($fileSize > 10 * 1024 * 1024) {
|
||||
$quality = 65;
|
||||
} else {
|
||||
$quality = $originalQuality;
|
||||
}
|
||||
|
||||
// 创建临时文件
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'compressed_');
|
||||
|
||||
// 保存压缩后的图片
|
||||
switch ($mime) {
|
||||
case 'image/jpeg':
|
||||
imagejpeg($image, $tempFile, $quality);
|
||||
break;
|
||||
case 'image/png':
|
||||
// PNG使用压缩级别(0-9),需要转换
|
||||
$pngQuality = 9 - round(($quality / 100) * 9);
|
||||
imagepng($image, $tempFile, $pngQuality);
|
||||
break;
|
||||
case 'image/gif':
|
||||
imagegif($image, $tempFile);
|
||||
break;
|
||||
}
|
||||
|
||||
// 释放内存
|
||||
imagedestroy($image);
|
||||
|
||||
// 检查压缩后文件大小,如果仍然大于3MB,继续压缩
|
||||
$compressedSize = filesize($tempFile);
|
||||
if ($compressedSize > 3 * 1024 * 1024) {
|
||||
// 递归压缩直到满足要求
|
||||
return $this->compressImage($tempFile, $compressedSize);
|
||||
}
|
||||
|
||||
return $tempFile;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user