图像处理
网站开发中需要经常处理图片,如课程缩略图,用户头像等,使用 PHP 处理图像非常简单。
配置环境
PHP 中图像处理需要 GD 库的支持。
在 windows 系统中修改 php.ini 文件,删除 extension=php_gd2.dll
前面的 ;
开启图像处理支持。
centos 中使用 yum install php-gd*
ubuntu 系统中使用 apt-get install php7.3-gd
检测 GD 库是否加载
$has = extension_loaded('GD');
var_dump($has);
使用方法
PHP 创建图像步骤
- 发送HTTP头信息,声明内容为图像。
- 创建画布
- 创建绘图所需要的颜色
- 绘图(填充画布、画圆、画方块、画线条、画布上写字)
- 输出图像
- 释放画布资源
头信息
通过 header() 函数告诉浏览器,输出的是一个图像而不是文本或 HTML,这样浏览器就可以正常显示图像了。
- header(‘Content-type: image/gif’);
- header(‘Content-type: image/jpeg’);
- header(‘Content-type: image/png’);
header('Content-type:image/jpeg');
readfile('user.jpeg');
创建画布
imageCreateTrueColor(width, height)
- 传入的两个参数分别为画布的宽和高,在绘图时超出宽高的部分将不予显示,且此尺寸即为生成图片文件时的尺寸。
- 返回值为资源类型。
设置颜色
imageColorAllocate(img_resource, R, G, B)
- 颜色从属于某个图像资源而存在。
- 颜色实际上是一个整型数值。
- 颜色的后三个参数需传入值的范围是 0~255。
填充颜色
imageFill(img_resource, x, y, color)
- (x,y) 表示从哪个点开始填充颜色的坐标
- 不填充画布的话,默认是黑色
header('Content-type:image/jpeg');
$res = imagecreatetruecolor(1000, 500);
$red = imagecolorallocate($res, 255, 0, 0);
imagefill($res, 0, 0, $red);
imagejpeg($res);
绘制矩形
绘制空心矩形
- imageRectangle(img_res,x1,y1,x2,y2,color)
header('Content-type:image/jpeg');
$res = imagecreatetruecolor(1000, 500);
$red = imagecolorallocate($res, 255, 0, 0);
$green = imagecolorallocate($res, 0, 255, 0);
imagefill($res, 0, 0, $red);
imagerectangle($res, 100, 100, 200, 200, $green);
imagejpeg($res);
绘制填充好的实心矩形
imageFilledRectangle(img_res, x1, y1, x2, y2, color)
- (x1,y1) 为左上角坐标,(x2,y2) 为右下角坐标
header('Content-type:image/jpeg');
$res = imagecreatetruecolor(1000, 500);
$red = imagecolorallocate($res, 255, 0, 0);
$green = imagecolorallocate($res, 0, 255, 0);
imagefill($res, 0, 0, $red);
imagefilledrectangle($res, 100, 100, 300, 300, $green);
imagejpeg($res);
绘制圆形
绘制空心圆形
- imageEllipse(img_res,x,y,h,color)
绘制填充好的实心圆
- imageFilledEllipse(img_res,x,y,w,h,color)
说明:
- (x,y) 为圆心坐标。w 为宽度,h 为高度
header('Content-type:image/jpeg');
$res = imagecreatetruecolor(500, 500);
$red = imagecolorallocate($res, 255, 0, 0);
$green = imagecolorallocate($res, 0, 255, 0);
imagefill($res, 0, 0, $red);
imageellipse($res, 250, 250, 100, 100, $green);
imagejpeg($res);
绘制线条
imageLine(img_res, x1, y1, x2, y2, color)
- (x1, y1) 为起始点坐标
- (x2, y2) 为结束点坐标
$res = imagecreatetruecolor(500, 500);
$red = imagecolorallocate($res, 255, 0, 0);
$green = imagecolorallocate($res, 0, 255, 0);
imagefill($res, 0, 0, $red);
imageline($res, 0, 0, 499, 499, $green);
imagepng($res);
绘制像素
bool imagesetpixel(resource $image, int $x, int $y, int $color)
- (x, y) 为点坐标
header('Content-type:image/jpeg');
$res = imagecreatetruecolor(500, 500);
$red = imagecolorallocate($res, 255, 0, 0);
$green = imagecolorallocate($res, 0, 255, 0);
imagefill($res, 0, 0, $red);
for ($i = 0; $i < 600; $i++) {
imagesetpixel($res, mt_rand(0, 500), mt_rand(0, 500), $green);
}
imagepng($res);
输出图像
输出不同格式的图像用不同的方法:
- imagegif(img_resource[, filename])
- imagejpeg(img_resource[, filename])
- imagepng(img_resource[, filename])
- imagebmp(img_resource[, filename])
- 当设置第二个参数时表示储存文件,如果存在同名文件会覆盖
释放图像
imageDestroy(img_resource)
- 图像输出完毕及时释放资源,把内存空间留给更需要的程序。
输入文本
array imagettftext(resource $image, float $size, float $angle, int $x, int $y, int $color, string $fontfile, string $text)
- 参数说明:图像资源,字体尺寸,角度,第一个字符的基本点(大概是字符的左下角),Y坐标(字体基线的位置),颜色,字体文件,文本字符串(UTF-8编码)
header('Content-type:image/png');
$res = imagecreatetruecolor(500, 500);
$red = imagecolorallocate($res, 255, 0, 0);
$green = imagecolorallocate($res, 0, 255, 0);
imagefill($res, 0, 0, $red);
$font = realpath('source.otf');
imagettftext($res, 50, 0, 0, 50, $green, $font, 'houdunren.com');
imagepng($res);
imagedestroy($res);
array imagettfbbox(float $size, float $angle, string $fontfile, string $text)
- 文本范围的盒子大小,可以方便控制文本输出位置
- 返回一个含有 8 个单元的数组表示了文本外框的四个角: | 变量 | 位置 | | —- | —- | | 0 | 左下角 X 位置 | | 1 | 左下角 Y 位置 | | 2 | 右下角 X 位置 | | 3 | 右下角 Y 位置 | | 4 | 右上角 X 位置 | | 5 | 右上角 Y 位置 | | 6 | 左上角 X 位置 | | 7 | 左上角 Y 位置 |
文字在画布右上角显示
$font = realpath('EBRIMA.TTF');
$text = '0x208.cc';
$size = 16;
$box = imagettfbbox($size, 0, $font, $text);
$width = $box[2] - $box[0];
$height = $box[0] - $box[6];
imagettftext($res, $size, 0, 500 - $width, $height, $green, $font, $text);
文字在画布中间显示
...
imagettftext($res, $size, 0, 250 - $width / 2, 250 - $height / 2, $green, $font, $text);
...
外部图像
打开图像文件
- imageCreateFromgif(filename/url)
- imageCreateFromjpeg(filename/url)
- imageCreateFrompng(filename/url)
- imageCreateFrombmp(filename/url)
- 返回一个资源类型
获得信息
imagesx(img_resource)
- 取得图像宽度
imagesy(img_resource)
- 取得图像高度
getimagesize(img_file)
- array getimagesize(string $filename [, array &$imageinfo])
- 取得图像大小
图像复制
拷贝图像的一部分
- bool 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)
拷贝并合并图像的一部分
- bool imagecopymerge ( resource $dst_im , resource $src_im , int $dst_x , int $dst_y , int $src_x , int $src_y , int $src_w , int $src_h , int $pct )
图片缩放
拷贝部分图像并调整大小
- bool imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
验证码
使用方法
# 后台code.php
include 'Captcha.php';
$code = new Captcha(100, 30, 20);
$code->make();
# 前台
<img src="code.php" alt="">
验证码类
<?php
class Captcha
{
protected $width;
protected $height;
protected $res;
protected $len = 4;
protected $font;
protected $size;
protected $code;
public function __construct(int $width = 100, int $height = 30, $size = 20)
{
$this->width = $width;
$this->height = $height;
$this->font = realpath('EBRIMA.TTF');
$this->size = $size;
}
public function make()
{
$res = imagecreatetruecolor($this->width, $this->height);
imagefill($this->res = $res, 0, 0, imagecolorallocate($res, 200, 200, 200));
$this->text();
$this->line();
$this->pix();
$this->render();
return $this->code;
}
protected function text()
{
$text = 'abcdefghigk123456789';
for ($i = 0; $i < $this->len; $i++) {
$x = $this->width / $this->len * $i;
$box = imagettfbbox($this->size, 0, $this->font, $text[$i]);
$this->code .= $code = strtoupper($text[mt_rand(0,strlen($text)-1)]);
imagettftext(
$this->res,
$this->size,
mt_rand(-20, 20),
$x,
$this->height / 2 + ($box[0] - $box[7]) / 2,
$this->textColor(),
$this->font,
$code
);
}
}
protected function pix()
{
for ($i = 0; $i < 300; $i++) {
imagesetpixel(
$this->res,
mt_rand(0, $this->width),
mt_rand(0, $this->height),
$this->color()
);
}
}
protected function line()
{
for ($i = 0; $i < 6; $i++) {
//线条宽度
imagesetthickness($this->res, mt_rand(1, 3));
imageline(
$this->res,
mt_rand(0, $this->width),
mt_rand(0, $this->height),
mt_rand(0, $this->width),
mt_rand(0, $this->height),
$this->color()
);
}
}
protected function color()
{
return imagecolorallocate($this->res, mt_rand(100, 200), mt_rand(100, 200), mt_rand(100, 200));
}
protected function textColor()
{
return imagecolorallocate($this->res, mt_rand(50, 150), mt_rand(50, 150), mt_rand(50, 150));
}
protected function render()
{
header('Content-type:image/png');
imagepng($this->res);
}
}
水印类
调用方式
<?php
include "Water.php";
$water = new Water("logo.png");
$water->make('sun.png', '2.png', 5);
水印类源码
<?php
class Water
{
//水印资源
protected $water;
//水印图片
public function __construct(string $water)
{
$this->water = $water;
}
//入口方法
public function make(string $image, string $filename = null, int $pos = 9)
{
$res = $this->resource($image);
$water = $this->resource($this->water);
$postion = $this->position($res, $water, $pos);
imagecopy($res, $water, $postion['x'], $postion['y'], 0, 0, imagesx($water), imagesy($water));
$this->showAction($image)($res, $filename ?: $image);
}
//获取资源对象
protected function resource($image)
{
$info = getimagesize($image);
$function = [1 => 'imagecreatefromgif', 2 => 'imagecreatefromjpeg', 3 => 'imagecreatefrompng'];
$call = $function[$info[2]];
return $call($image);
}
//根据类型输出图片
protected function showAction(string $image)
{
$info = getimagesize($image);
$function = [1 => 'imagegif', 2 => 'imagejpeg', 3 => 'imagepng'];
return $function[$info[2]];
}
//位置
protected function position($des, $res, int $pos)
{
$info = ['x' => 0, 'y' => 0];
switch ($pos) {
case 1:
break;
case 2:
$info['x'] = (imagesx($des) - imagesx($res)) / 2;
break;
case 3:
$info['x'] = (imagesx($des) - imagesx($res));
break;
case 4:
$info['y'] = (imagesy($des) - imagesy($res)) / 2;
break;
case 5:
$info['x'] = (imagesx($des) - imagesx($res)) / 2;
$info['y'] = (imagesy($des) - imagesy($res)) / 2;
break;
}
return $info;
}
}
缩略图
调用方式
include 'Resize.php';
$image = new Resize;
$image->make('sun.png', '1.jpeg', 200, 200, 3);
缩略图类
<?php
class Resize
{
public function make(string $file, string $to = null, int $width = 200, int $height = 200, int $type = 3)
{
$image = $this->resource($file);
$info = $this->size($width, $height, imagesx($image), imagesy($image), $type);
$res = imagecreatetruecolor($info[0], $info[1]);
imagecopyresampled($res, $image, 0, 0, 0, 0, $info[0], $info[1], $info[2], $info[3]);
header('Content-type:image/jpeg');
imagejpeg($res);
}
protected function size($rw, $rh, $iw, $ih, int $type)
{
switch ($type) {
case 1:
//固定宽度,高度自动
$rh = $rw / $iw * $ih;
break;
case 2:
//高度固定,宽度自动
$rw = $rh / $ih * $iw;
break;
case 3:
//固定宽度,高度裁切
$ih = $iw / $rw * $rh;
break;
default:
if (($iw / $rw) > ($ih / $rh)) {
$iw = $ih / $rh * $rh;
} else {
$ih = $iw / $rw * $rw;
}
}
return [$rw, $rh, $iw, $ih];
}
protected function resource(string $image)
{
if (!file_exists($image) || getimagesize($image) === false) {
throw new Exception("file dont exists or it's not an image file");
}
$functions = [1 => 'imagecreatefromgif', 2 => 'imagecreatefromjpeg', 3 => 'imagecreatefrompng'];
$info = getimagesize($image);
$call = $functions[$info[2]];
return $call($image);
}
}