王新阳

wangxinyang

PHP按目标比例和尺寸缩小并裁切图片

重点是关于图片翻转、旋转部分的处理

/**
 * 按目标比例和尺寸缩小并裁切图片,如果原图尺寸小于目标尺寸,则只按比例裁切
 * @param $img_name 原图片名称(不是路径)
 * @param $width 目标图片宽度,如果原图宽度不等于目标宽度,则原图按目标比例缩放后再裁切
 * @param $width 目标图片高度
 */
private function img_convert_do($img_name, $width, $height){
	//$new_name=date('YmdHis').my_str_shuffle(5,'number,lower').substr($img_name,strrpos($img_name,'.'));
	$new_name=date('YmdHis').my_str_shuffle(5,'number,lower').'.jpg';
	$old_img=SRC_PATH.$img_name;
	$new_img=DST_PATH.$new_name;

/*
exif_read_data($old_img)结果如下:
Array
(
    [FileName] => a.jpg
    [FileDateTime] => 1750318340
    [FileSize] => 17175
    [FileType] => 2
    [MimeType] => image/jpeg
    [SectionsFound] => ANY_TAG, IFD0, EXIF
    [COMPUTED] => Array
        (
            [html] => width="536" height="404"
            [Height] => 404
            [Width] => 536
            [IsColor] => 1
            [ByteOrderMotorola] => 1
        )

    [Orientation] => 8
    [Exif_IFD_Pointer] => 318
    [UndefinedTag:0xEA1C] => 
)
*/
	$exif_res=@exif_read_data($old_img);
	if($exif_res===false){
		$size_arr = @getimagesize($old_img);
		if(!is_array($size_arr)){
			exit('图片尺寸获取失败:'.$img_name);
		}
		$w = $size_arr[0];
		$h= $size_arr[1];
		//printr($size_arr);
	}else{
		$w=$exif_res['COMPUTED']['Width'];
		$h=$exif_res['COMPUTED']['Height'];
		//printr($exif_res);
	}
	
	$source = imagecreatefromstring(file_get_contents($old_img));
	switch(array_item($exif_res,'Orientation')){
		case 1: //无翻转
			break;
		case 2: //水平翻转
			imageflip($source,IMG_FLIP_HORIZONTAL);
			break;
		case 3: //旋转180度
			$source = imagerotate($source,180,0);
			break;
		case 4: //垂直翻转
			imageflip($source,IMG_FLIP_VERTICAL);
			break;
		case 5: //顺时针旋转90度+水平翻转
			$source = imagerotate($source,-90,0);
			imageflip($source,IMG_FLIP_HORIZONTAL);
			break;
		case 6: //顺时针旋转90度
			$source = imagerotate($source,-90,0);
			break;
		case 7: //逆时针旋转90度+水平翻转
			$source = imagerotate($source,90,0);
			imageflip($source,IMG_FLIP_HORIZONTAL);
			break;
		case 8: //逆时针旋转90度
			$source = imagerotate($source,90,0);
			break;
		default: //png等无方向属性
	}
	switch(array_item($exif_res,'Orientation')){
		case 5:
		case 6:
		case 7:
		case 8:
			//旋转90度的图片扶正后要宽高值要互换
			$tmp=$w;
			$w=$h;
			$h=$tmp;
			unset($tmp);
			break;
	}
	$src_w=$w;
	$src_h=$h;

	if($w/$h < $width/$height){
		$h=ceil($w*$height/$width);
	}else if($w/$h > $width/$height){
		$w=ceil($width*$h/$height);
	}else{
		//比例一致时,如果原图小于100K则直接复制
		if(filesize($old_img)<100*1024){
			copy($old_img,$new_img);
			return $new_name;
		}
	}
	if($w<$width){
		$width=$w;
		$height=$h;
	}

	//echo $w,'x',$h,'<br>',$width,'x',$height,'<br>';return;
	
	//新建真彩色图像
	$im = imagecreatetruecolor($width, $height);
	//为图像分配颜色
	//$color = imagecolorallocate($im, 255,255,255);
	//从指定坐标开始填充颜色
	//imagefill($im, 0,0, $color);
	//从字符串的图像流中新建图像,可以自动识别文件类型,但是比 imagecreatefromjpeg 等多消耗内存
	//totxt($old_img, FCPATH.'photo.txt', true);
	//$source = imagecreatefromstring(file_get_contents($old_img));
/*
从 x、y 坐标 src_x、src_y 开始,将 src_image 的一部分复制到 dst_image 上,
宽度为 src_width,高度为 src_height。定义的部分将被复制到 x,y 坐标 dst_x 和 dst_y 上。
imagecopy(
    GdImage $dst_image,
    GdImage $src_image,
    int $dst_x,
    int $dst_y,
    int $src_x,
    int $src_y,
    int $src_width,
    int $src_height
): bool

从 src_image 位置(src_x、src_y)开始取出一个宽度为 src_width 高度为 src_height 的矩形区域,
并将其放置在 dst_image 中位置从(dst_x、dst_y)开始宽度为 dst_width 高度为 dst_height 的矩形区域中。
imagecopyresampled(
    GdImage $dst_image,
    GdImage $src_image,
    int $dst_x,
    int $dst_y,
    int $src_x,
    int $src_y,
    int $dst_width,
    int $dst_height,
    int $src_width,
    int $src_height
): bool

输出图象到浏览器或文件
image 由图象创建函数(例如imagecreatetruecolor())返回的 GdImage 对象。
file 文件保存的路径或者已打开的流资源(此方法返回后自动关闭该流资源),如果未设置或为 null,将会直接输出原始图象流。
quality 为可选项,范围从 0(最差质量,文件最小)到 100(最佳质量,文件最大)。默认值(-1)使用 IJG 默认的质量值(大约 75)。
imagejpeg(GdImage $image, resource|string|null $file = null, int $quality = -1): bool
*/
	//执行剪裁(高质量重采样)
	//($src_h-$h)/4 此处是4而不是2的原因:尽量从上边开始剪裁,避免上边剪裁过大,导致头到照片顶部留白太小甚至剪到头
	imagecopyresampled($im, $source, 0,0, $src_w>$w?($src_w-$w)/2:0,$src_h>$h?($src_h-$h)/3:0, $width,$height, $w,$h);
	imagedestroy($source);
	
	//保存到文件
	imagejpeg($im, $new_img, 90);
	imagedestroy($im);
	//exit('ok');
	return $new_name;
}
2025-08-02
2025-08-02 星期六 农历六月初九