最近服务器上的图片越来越多了,并且前期并没有对用户上传的图片进行压缩处理,导致服务器硬盘有点吃紧了。心疼钱钱嘛,于是琢磨着怎么将他们压缩一下,减少图片体积,腾点空间出来。重要的是,还能节省不少带宽。
说干就干,先是到搜索引擎搜搜看别人是怎么处理的,结果搜了一圈,没找到合适的方案,大部分文章都是抄来抄去,参考意义不大。
于是到GitHub上翻翻,看看有没有现成的直接可用项目。由于目前的项目是php写的,所以理所当然的想着现成的php方案。结果翻了一圈没找到,倒是找到了tinypng/tinyjpg。不过这些都是调用的别人的api,不是我想要的结果。
最终功夫不负有心人,终于分别给jpg、png、gif格式的图片找到了压缩的方法。
实际上,仅仅依靠php是搞不定的。我们需要分别安装针对不同图片格式的压缩工具。
gif图片的压缩工具是gifsicle
,jpg图片的压缩工具是jpegoptim
,png的图片压缩工具是pngquant
。因为我的项目只允许使用这三种图片,所以,这里我只研究这三种图片的压缩方式。
我的服务器是centos
服务器,因此,这里只介绍在centos服务器上如何安装和使用图片压缩工具。
安装 gifsicle jpegoptim pngquant
yum install gifsicle jpegoptim pngquant
至此,需要安装的软件安装好了,我们再编写php代码,来调用他们实现压缩功能:
<?php
/**
* 这是一个图片压缩类文件
* 支持gif、jpg、png压缩
* @ author www.kandaoni.com
*/
class cls_compress
{
public $file;
public $new_file;
public $infos;
public $cmd;
public $errors;
protected $force = true;
protected $quality = null;
protected $quality_max = null;
protected $progressive = false;
protected $extension;
private static $extensionAlias = array(
'jpeg' => 'jpg'
);
public function __construct($file, $new_file = null)
{
$this->file = $file;
if(!$new_file) {
$this->new_file = $this->file;
} else {
$this->new_file = $new_file;
}
if($this->new_file != $this->file) {
if(copy($this->file, $this->new_file)) {
@chmod($this->new_file, 0777);
} else {
$this->setError('Can not copy : ' . $this->file);
}
}
$this->extension = self::getExtension($file);
}
public static function getExtension($file)
{
$info = new SplFileInfo($file);
$extension = $info->getExtension();
return array_key_exists($extension, self::$extensionAlias) ? self::$extensionAlias[$extension] : $extension;
}
public function exec()
{
$this->getCommand();
if ($this->cmd) {
exec($this->cmd, $info);
}
$this->getInfos();
}
public static function getFormatSize($bytes, $decimals = 1)
{
$size = array('b', 'ko', 'Mo');
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[(int)$factor];
}
/**
* 根据不同的图片格式,添加不同的命令。
*/
public function getCommand()
{
if($this->extension == 'gif') {
$this->addCommand('gifsicle ' . $this->new_file . ' -o ' . $this->new_file . ' -O3');
} else if($this->extension == 'jpg') {
$this->addCommand('jpegoptim ' . $this->new_file . ' --strip-all -o --m ' . $this->quality);
} else if($this->extension == 'png') {
$this->addCommand(
'pngquant ' . $this->new_file .' -o ' . $this->new_file.' --force'.
($this->quality && $this->quality_max ? ' --quality=' . $this->quality . '-' . $this->quality_max : '')
);
}
}
public function setQuality($min, $max = null)
{
if ($min >= 0 && $min <= 100) {
$this->quality = $min;
}
if ($max && $max >= 0 && $max <= 100 && $max > $this->quality) {
$this->quality_max = $max;
}
return $this;
}
public function setSize($w, $h = null, $crop = false)
{
if (!$h) {
$h = $w;
}
$size = getimagesize($this->file);
if ($w > $size[0] && $h > $size[1]) {
return false;
}
$cmd = 'convert ' . $this->new_file . ' -resize ' . $w . 'x' . $h;
if ($crop) {
$cmd .= '^ -gravity center -extent ' . $w . 'x' . $h;
}
$cmd .= ' ' . $this->new_file;
$this->addCommand($cmd);
return $this;
}
protected function addCommand($cmd)
{
$this->cmd .= $cmd . ';' . "\n";
}
public function getInfos()
{
if (!empty($this->errors)) {
return array('errors' => $this->errors);
} else {
$original_size = filesize($this->file);
$new_size = filesize($this->new_file);
$saved_size = $original_size - $new_size;
$percent_saved = 100 - ((100 * $new_size) / $original_size);
return array(
'original_size' => self::getFormatSize($original_size),
'new_size' => self::getFormatSize($new_size),
'saved_size' => self::getFormatSize($saved_size),
'saved_percent' => round($percent_saved, 2),
'file' => basename($this->file),
'new_file' => basename($this->new_file)
);
}
}
public function setError($error)
{
$this->errors[] = $error;
}
}
上面的处理类中,允许传入原图和新图片。如果没有传入新图片地址,则会覆盖原图。再根据不同的图片格式,调用不同的命令。最终执行结果,可以通过调用getInfos获得,如果有错误,getInfos会返回错误信息,否则就返回压缩处理后的压缩率等信息。
调用方法:
$imageFile = "/data/wwwroot/www/test/test.png";
$compress = new cls_compress($imageFile);
$compress->setQuality(85)->exec();
print_r($compress->getInfos());
上面的代码,会将test.png图片按质量85%来压缩图片,并打印质量信息。实际上服务器运行不需要打印,只需要执行完就可以了。执行完了后,压缩后的图片,会替换掉原图。如果需要压缩后的图片另外存储,则可以传入第二个参数:
$imageFile = "/data/wwwroot/www/test/test.png";
$destFile = "/data/wwwroot/www/test/new_test.png";
$compress = new cls_compress($imageFile, $destFile);
$compress->setQuality(85)->exec();
print_r($compress->getInfos());
这样子,压缩后的图片就会保存成new_test.png了。
上面的图片压缩类,可以单独调用,也可以