PHP实现图片压缩显示的基本原理
图片压缩显示的核心在于通过PHP的GD库或Imagick扩展对原始图片进行缩放和优化处理,生成更小尺寸或更低质量的图片文件。GD库是PHP内置的图像处理库,而Imagick功能更强大但需要额外安装。
图片压缩通常涉及以下步骤:读取原始图片、计算缩放比例、创建新画布、绘制缩放后的图像、输出或保存压缩后的图片。通过调整压缩参数,可以在文件大小和图片质量之间找到平衡。
使用GD库压缩图片
GD库是PHP默认支持的图像处理库,适合简单的图片压缩需求。以下是一个完整的GD库压缩示例:
function compressImageWithGD($sourcePath, $targetPath, $maxWidth, $maxHeight, $quality = 75) {
// 获取原始图片信息
list($origWidth, $origHeight, $type) = getimagesize($sourcePath);
// 计算缩放比例
$ratio = min($maxWidth/$origWidth, $maxHeight/$origHeight);
$newWidth = $origWidth * $ratio;
$newHeight = $origHeight * $ratio;
// 创建新画布
$newImage = imagecreatetruecolor($newWidth, $newHeight);
// 根据不同类型创建原始图像资源
switch($type) {
case IMAGETYPE_JPEG:
$sourceImage = imagecreatefromjpeg($sourcePath);
break;
case IMAGETYPE_PNG:
$sourceImage = imagecreatefrompng($sourcePath);
imagealphablending($newImage, false);
imagesavealpha($newImage, true);
break;
case IMAGETYPE_GIF:
$sourceImage = imagecreatefromgif($sourcePath);
break;
default:
return false;
}
// 缩放图像
imagecopyresampled($newImage, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $origWidth, $origHeight);
// 保存压缩后的图片
switch($type) {
case IMAGETYPE_JPEG:
imagejpeg($newImage, $targetPath, $quality);
break;
case IMAGETYPE_PNG:
imagepng($newImage, $targetPath, round(9 * (100 - $quality) / 100));
break;
case IMAGETYPE_GIF:
imagegif($newImage, $targetPath);
break;
}
// 释放内存
imagedestroy($sourceImage);
imagedestroy($newImage);
return true;
}
// 使用示例
compressImageWithGD('original.jpg', 'compressed.jpg', 800, 600, 80);
使用Imagick扩展压缩图片
Imagick扩展提供了更专业的图像处理能力,适合需要高质量压缩的场景:
function compressImageWithImagick($sourcePath, $targetPath, $maxWidth, $maxHeight, $quality = 80) {
try {
$image = new Imagick($sourcePath);
// 设置压缩质量
$image->setImageCompressionQuality($quality);
// 保持宽高比缩放
$image->resizeImage($maxWidth, $maxHeight, Imagick::FILTER_LANCZOS, 1, true);
// 优化图片
$image->stripImage(); // 移除EXIF等元数据
$image->setInterlaceScheme(Imagick::INTERLACE_JPEG); // 渐进式JPEG
// 根据扩展名保存
$ext = strtolower(pathinfo($targetPath, PATHINFO_EXTENSION));
if ($ext == 'jpg' || $ext == 'jpeg') {
$image->setImageFormat('jpeg');
} elseif ($ext == 'png') {
$image->setImageFormat('png');
}
$image->writeImage($targetPath);
$image->destroy();
return true;
} catch (Exception $e) {
return false;
}
}
// 使用示例
compressImageWithImagick('original.png', 'compressed.png', 800, 600, 85);
图片质量与文件大小的平衡
图片压缩需要在质量和文件大小之间找到平衡点。以下是一些实用技巧:
- JPEG格式适用于照片类图像,质量参数通常在60-85之间
- PNG格式适合需要透明度的图像,压缩主要通过减少颜色深度实现
- GIF格式适合简单动画,但压缩率较低
// 动态调整JPEG质量以达到目标文件大小
function compressToTargetSize($sourcePath, $targetPath, $targetSizeKB) {
$quality = 90; // 初始质量
do {
compressImageWithGD($sourcePath, $targetPath, 1000, 1000, $quality);
$currentSizeKB = filesize($targetPath) / 1024;
$quality -= 5;
} while ($currentSizeKB > $targetSizeKB && $quality > 10);
}
// 使用示例
compressToTargetSize('large_image.jpg', 'optimized.jpg', 200); // 目标200KB
批量处理图片压缩
对于需要处理大量图片的场景,可以结合目录遍历实现批量压缩:
function batchCompressImages($sourceDir, $targetDir, $maxWidth, $maxHeight, $quality = 80) {
if (!file_exists($targetDir)) {
mkdir($targetDir, 0755, true);
}
$files = scandir($sourceDir);
foreach ($files as $file) {
if ($file == '.' || $file == '..') continue;
$sourcePath = $sourceDir . '/' . $file;
$targetPath = $targetDir . '/' . $file;
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
compressImageWithGD($sourcePath, $targetPath, $maxWidth, $maxHeight, $quality);
}
}
}
// 使用示例
batchCompressImages('uploaded_images', 'compressed_images', 1024, 768, 75);
浏览器直接输出压缩图片
有时可能需要直接将压缩后的图片输出到浏览器而不保存文件:
function outputCompressedImage($imagePath, $maxWidth, $maxHeight, $quality = 75) {
list($origWidth, $origHeight, $type) = getimagesize($imagePath);
$ratio = min($maxWidth/$origWidth, $maxHeight/$origHeight);
$newWidth = $origWidth * $ratio;
$newHeight = $origHeight * $ratio;
$newImage = imagecreatetruecolor($newWidth, $newHeight);
switch($type) {
case IMAGETYPE_JPEG:
$sourceImage = imagecreatefromjpeg($imagePath);
header('Content-Type: image/jpeg');
break;
case IMAGETYPE_PNG:
$sourceImage = imagecreatefrompng($imagePath);
imagealphablending($newImage, false);
imagesavealpha($newImage, true);
header('Content-Type: image/png');
break;
case IMAGETYPE_GIF:
$sourceImage = imagecreatefromgif($imagePath);
header('Content-Type: image/gif');
break;
default:
return false;
}
imagecopyresampled($newImage, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $origWidth, $origHeight);
switch($type) {
case IMAGETYPE_JPEG:
imagejpeg($newImage, null, $quality);
break;
case IMAGETYPE_PNG:
imagepng($newImage, null, round(9 * (100 - $quality) / 100));
break;
case IMAGETYPE_GIF:
imagegif($newImage);
break;
}
imagedestroy($sourceImage);
imagedestroy($newImage);
}
// 使用示例
outputCompressedImage('photo.jpg', 800, 600, 80);
性能优化建议
图片压缩可能消耗较多服务器资源,以下方法可以优化性能:
- 缓存已压缩的图片,避免重复处理
- 使用PHP的OPcache加速脚本执行
- 对大图片处理设置适当的超时限制
- 考虑使用队列系统异步处理大量图片
// 带缓存功能的图片压缩
function cachedImageCompress($sourcePath, $cachePath, $maxWidth, $maxHeight, $quality = 80) {
$cacheKey = md5($sourcePath.$maxWidth.$maxHeight.$quality);
$cachedFile = $cachePath.'/'.$cacheKey.'.jpg';
if (file_exists($cachedFile) && (filemtime($cachedFile) > filemtime($sourcePath))) {
return $cachedFile;
}
if (compressImageWithGD($sourcePath, $cachedFile, $maxWidth, $maxHeight, $quality)) {
return $cachedFile;
}
return false;
}
// 使用示例
$compressedImage = cachedImageCompress('original.jpg', 'cache', 800, 600, 85);
if ($compressedImage) {
header('Content-Type: image/jpeg');
readfile($compressedImage);
}