186 lines
5.5 KiB
PHP
186 lines
5.5 KiB
PHP
<?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;
|
||
}
|
||
|
||
} |