PHP图片合成实践

最近有小朋友问我,电商网站上传listing 时,商品图片能否基于模板,把另一张商品图片通过程序的方式自动放到模板图片上,并且可以自动在合成的图片上某个位置写些商品介绍的文字,这样的话,就可以减少设计师或美工P图的工作量。以前大家常见的图片处理代码是利用gd库对图片进行缩放,比如上传一张图片的时候,顺带生成图片的缩略图或是在图片中打个水印等等,没有实现过图片合成这样的功能,所以花了点时间查了些资料自己实现了个简单的效果。

下面进入正题,如何实现两张图(一张模板,一张子图)的合并,并且往合成图片上写些文字,废话不多说,先上简易代码:

<?php
header('Content-type:image/jpeg; charset=utf-8');
if(!empty($_FILES)){
	$remark = $_POST['remark'];
	if (count($_FILES['demofile']['name']) == 2) {
	$filename1 = $_FILES['demofile']['name'][0];
	$filename2 = $_FILES['demofile']['name'][1];
        $files1 = explode('.',$filename1);
	$type1 = end($files1);
	$time1 = date('YmdHis');
	$head = '/tmp/';
	$destination1 = $head.$time1.'_'.rand(100000, 999999).'.'.$type1;

    //上传图片1
	move_uploaded_file($_FILES['demofile']['tmp_name'][0], $destination1);

    $files2 = explode('.',$filename2);
	$type2 = end($files2);
	$time2 = date('YmdHis');
	$destination2 = $head.$time2.'_'.rand(100000, 999999).'.'.$type2;

    //上传图片2
	move_uploaded_file($_FILES['demofile']['tmp_name'][1], $destination2);

    //background.jpg 背景图,程序的目的是将上传的图片放在背景图上
	$imageDestination = './background.jpg'; //主视图,也就是白云飘飘这张主图
	$imageDestination = imagecreatefromjpeg($imageDestination);

	//创建图片资源句柄
	$imageSource1 = imagecreatefromjpeg($destination1);

	// $imageSource1 = $destination1; //复制并需旋转的小图
	$imageSource2 = imagecreatefromjpeg($destination2);
	
   //关键代码,将imageSource1图片合到imageDestination图片资源上
	imagecopy($imageDestination, $imageSource1, 110, 150, 0, 0, imagesx($imageSource1), imagesy($imageSource1));

   //将imageSource2图片合到imageDestination图片资源上
	imagecopy($imageDestination, $imageSource2, 50, 595, 0, 0, imagesx($imageSource2), imagesy($imageSource2));

    //合成完,如果要将图片另存,则利用imagejpeg的第二个参数实现
	// imagejpeg($imageDestination, $head . "merge.jpg"); //输出图片
	$black = imagecolorallocate($imageDestination, 65, 65, 65);

    //关键代码,往imageDestination图片资源上写remark
	imagettftext($imageDestination, 12, 0, 320, 190, $black,'/tmp/msyh.ttf', $remark);
	imagejpeg($imageDestination);
} else {
	echo "你没有上传两张图片";
}

以上代码的作用是上传两张图片,将上传的图片放到background.jpg 这张背景图的指定位置上,并且往background背景指定位置上写上说明文字,就这么简单,当然上述代码很粗糙,没有兼容不同的图片格式,没有判断图片大小,没有对图片的比例判断,如果大于某个比例,没有缩放,没有考虑说明文字的长度,会不会长了自动折行等等,我们在这里只是讲个大概的原理,细节需要自行去完善。

代码关键回顾,核心方法如下,主要利用了imagecopy(将src_im copy到dst_im上),imagejpeg(从image图像创建jpeg图像),imagettftext(将文字写入image中)这三个方法:

  • imagecopy ( resource $dst_im , resource $src_im , int $dst_x , int $dst_y , int $src_x , int $src_y , int $src_w , int $src_h ) 方法: 将 src_im 图像中坐标从 src_xsrc_y 开始,宽度为 src_w,高度为 src_h 的一部分拷贝到 dst_im 图像中坐标为 dst_x 和 dst_y 的位置上
  • imagejpeg ( resource $image [, string $filename [, int $quality ]] ):从 image 图像以 filename 为文件名创建一个 JPEG 图像
  • imagettftext ( resource $image , float $size , float $angle , int $x , int $y , int $color , string $fontfile , string $text ) : 使用 TrueType 字体将 指定的 text 写入图像。

当然,这种合成后的效果,取决于原始图片和模板之间的色差及融入度。所以图片和模板的颜色要一致,程序只是简单将A放到B的某个位置上,而无法智能的像设计师或美工一样P图,否则设计师就失业了。