两种生成缩略图策略


编	写:袁	亮
时	间:2015-07-13
说	明:生成缩略图的两种策略

一、为什么需要压缩图片?
	1、在各种web应用中,上传头像是一个非常常见的功能,比如头像、比如相册等等
	2、用户上传的图片一般都很大,现在的手机拍的图片,基本上都是2-3M,如果是相机,6-7M,10来M也很正常
	3、10M的图片,按现在用户的平均网速8M来说,那就是10MB/8Mb/s=10*8Mb/(8Mb/s)=10秒,浏览器显示一张照片就需要10秒,完全不能接受
	4、一个网页或者界面,一般都会显示很多张图片,而且每张图片其实只显示了一个很小的尺寸
	5、带宽费用很贵,因此图片显示,99%的地方都是显示的缩略图
	
二、两种压缩图片策略(图片不变形,变形的压缩不考虑,线上不允许使用)
	1、将原图压缩生成一个指定宽高的图片
		1.1 常见于头像等地方
		1.2 生成的图片宽高固定,图片可能被裁减,很多时候需要使用js插件,让用户拖拽,确定裁减到什么位置
		
	2、将原图压缩,宽高分别不能搞过某个值
		2.1 相册等大多数情况
		2.2 图片不会被裁减,但是生成出来的图片宽高不确定
		
三、php具体实现裁减
	//引用php函数
	include_once("image_function.php");
	
	$old_src = '6.jpg';
	$new_src = 'tmp/2013/02/27/2.jpg';
	$new_width = 400;
	$new_height = 300;
	mkdir('tmp/2013/02/27',777,1);
	1、方案1
		$res = cutPhotoDesign($old_src,$new_src,$new_width,$new_height,$rate=100);
	2、方案2
		$res = cutPhoto($old_src,$new_src,$new_width,$new_height,$rate=100);

四、nginx裁图模块
	1、使用程序来裁图,会遇到几个问题:
		1.1 如果再增加一个缩略图尺寸,则需要对原来的所有图片重新处理一次,很麻烦
		1.2 压缩图片,会使用户上传处理速度变慢
		1.3 需要存储非常多份的缩略图
	2、nginx有个扩展,阿里开源的,可以实现上面程序中的两种切图效果
		2.1 找运维同事帮忙部署
		2.2 nginx切图,访问缩略图的时候,nginx会看,是否已经有裁减过该尺寸的图片,如果有,直接访问,没有则裁减并缓存
		2.3 配置的时候,缩略图规则写到最后
			比如原图访问			http://***/***/a.jpg
			则缩略图规则为			http://***/***/a.jpg_600x400 
	
	
	

php压缩图片函数

/*
*编	写:袁	亮
*时	间:2013-02-27
*功	能:常见的两种缩略图生成策略实现,图片不允许变形,在生成缩略图之前需要确保图片存放目录存在并有写权限
	   可以调用createDirs创建目录并赋予相应的权限,该函数支持多级目录
	   在window下测试时处理大图片可能会出现内存不足,可以使用ini_set('memory_limit', '12M');更改内存限制
*/

function createDirs($dir,$model=0777){//创建多级目录
	return is_dir($dir) or createDirs(dirname($dir),$model) and mkdir($dir,$model);
}
/*
*生成一张给定宽高的缩略图,超出部分进行居中截图,只支持jpg,gif,png格式,生成的是jpg格式图片
@old_src:源图地址
@new_src:缩略图地址
@new_width:缩略图宽
@new_height:缩略图高
@rate:图片质量,0-100,可选参数,默认100
#返回值:1:缩略图生成成功,-1:不支持该图片类型,-2:图片文件错误,-3:缩略图生成失败
*/
function cutPhotoDesign($old_src,$new_src,$new_width,$new_height,$rate=100){
	$old_info = getimagesize($old_src);
	switch($old_info[2]){
		case 1:$im = imagecreatefromgif($old_src);break;
		case 2:$im = imagecreatefromjpeg($old_src);break;
		case 3:$im = imagecreatefrompng($old_src);break;
		default:return -1;
	}
	
	if(!$im){
		return -2;
	}
	$old_width = imagesx($im);
	$old_height = imagesy($im);
	
	if($old_width<=$new_width && $old_height<=$new_height){//图片过小,直接原图显示
		$res = copy($old_src,$new_src);
		imagedestroy($im);
		return $res?1:-3;
	}

	$x_rate = $old_width/$new_width;//计算压缩图片尺寸,以及截图开始位置
	$y_rate = $old_height/$new_height;
	if($x_rate<$y_rate){//宽度优先压缩
		$dst_x = $new_width;
		$dst_y = ceil($old_height/$x_rate);
		$new_start_x = 0;
		$new_start_y = ($dst_y-$new_height)/2;
	}else{//高度优先压缩
		$dst_x = ceil($old_width/$y_rate);
		$dst_y = $new_height;
		$new_start_x = ($dst_x-$new_width)/2;
		$new_start_y = 0;
	}
	
	$newim = imagecreatetruecolor($dst_x,$dst_y);//等比例压缩图片,将图片的宽或者高压缩到指定参数
	imagecopyresampled($newim,$im,0,0,0,0,$dst_x,$dst_y,$old_width,$old_height);

	$cutim = imagecreatetruecolor($new_width,$new_height);//将宽高都固定成指定参数,超出的部分居中截图
	imagecopyresampled($cutim,$newim,0,0,$new_start_x,$new_start_y,$new_width,$new_height,$new_width,$new_height);
	$res = imagejpeg($cutim,$new_src,$rate);//对图像进行截图

	imagedestroy($im);
	imagedestroy($newim);
	imagedestroy($cutim);
	return $res?1:-3;
}
/*
*生成一张宽高不超过给定参数的缩略图,只支持jpg,gif,png格式,生成的是jpg格式图片
@old_src:源图地址
@new_src:缩略图地址
@new_width:缩略图宽
@new_height:缩略图高
@rate:图片质量,0-100,可选参数,默认100
#返回值:1:缩略图生成成功,-1:不支持该图片类型,-2:图片文件错误,-3:缩略图生成失败
*/
function cutPhoto($old_src,$new_src,$new_width,$new_height,$rate=100){
	$old_info = getimagesize($old_src);
	switch($old_info[2]){
		case 1:$im = imagecreatefromgif($old_src);break;
		case 2:$im = imagecreatefromjpeg($old_src);break;
		case 3:$im = imagecreatefrompng($old_src);break;
		default:return -1;
	}
	
	if(!$im){
		return -2;
	}
	$old_width = imagesx($im);
	$old_height = imagesy($im);
	
	if($old_width<=$new_width && $old_height<=$new_height){//图片过小,直接原图显示
		$res = copy($old_src,$new_src);
		imagedestroy($im);
		return $res?1:-3;
	}
	
	$x_rate = $old_width/$new_width;//计算缩略图实际尺寸
	$y_rate = $old_height/$new_height;	
	if($x_rate<$y_rate){
		$dst_x = ceil($old_width/$y_rate);
		$dst_y = $new_height;
	}else{
		$dst_x = $new_width;
		$dst_y = ceil($old_height/$x_rate);
	}
	
	$newim = imagecreatetruecolor($dst_x,$dst_y);//按实际大小生成一张画布
	$bg = imagecolorallocate($newim,255,255,255);//白色背景
	imagecopyresampled($newim,$im,0,0,0,0,$dst_x,$dst_y,$old_width,$old_height);//将图片内容复制到新画布中
	$res = imagejpeg($newim,$new_src,$rate);//将画布中的内容写入文件
	
	imagedestroy($im);
	imagedestroy($newim);
	return $res?1:-3;
}