图像处理

网站开发中需要经常处理图片,如课程缩略图,用户头像等,使用 PHP 处理图像非常简单。

配置环境

PHP 中图像处理需要 GD 库的支持。

在 windows 系统中修改 php.ini 文件,删除 extension=php_gd2.dll 前面的 ; 开启图像处理支持。

centos 中使用 yum install php-gd*

ubuntu 系统中使用 apt-get install php7.3-gd

检测 GD 库是否加载

  1. $has = extension_loaded('GD');
  2. var_dump($has);

使用方法

PHP 创建图像步骤

  1. 发送HTTP头信息,声明内容为图像。
  2. 创建画布
  3. 创建绘图所需要的颜色
  4. 绘图(填充画布、画圆、画方块、画线条、画布上写字)
  5. 输出图像
  6. 释放画布资源

头信息

通过 header() 函数告诉浏览器,输出的是一个图像而不是文本或 HTML,这样浏览器就可以正常显示图像了。

  • header(‘Content-type: image/gif’);
  • header(‘Content-type: image/jpeg’);
  • header(‘Content-type: image/png’);
    1. header('Content-type:image/jpeg');
    2. readfile('user.jpeg');

创建画布

imageCreateTrueColor(width, height)

  • 传入的两个参数分别为画布的宽和高,在绘图时超出宽高的部分将不予显示,且此尺寸即为生成图片文件时的尺寸。
  • 返回值为资源类型。

设置颜色

imageColorAllocate(img_resource, R, G, B)

  • 颜色从属于某个图像资源而存在。
  • 颜色实际上是一个整型数值。
  • 颜色的后三个参数需传入值的范围是 0~255。

填充颜色

imageFill(img_resource, x, y, color)

  • (x,y) 表示从哪个点开始填充颜色的坐标
  • 不填充画布的话,默认是黑色
  1. header('Content-type:image/jpeg');
  2. $res = imagecreatetruecolor(1000, 500);
  3. $red = imagecolorallocate($res, 255, 0, 0);
  4. imagefill($res, 0, 0, $red);
  5. imagejpeg($res);

绘制矩形

绘制空心矩形

  • imageRectangle(img_res,x1,y1,x2,y2,color)
    1. header('Content-type:image/jpeg');
    2. $res = imagecreatetruecolor(1000, 500);
    3. $red = imagecolorallocate($res, 255, 0, 0);
    4. $green = imagecolorallocate($res, 0, 255, 0);
    5. imagefill($res, 0, 0, $red);
    6. imagerectangle($res, 100, 100, 200, 200, $green);
    7. imagejpeg($res);

绘制填充好的实心矩形

imageFilledRectangle(img_res, x1, y1, x2, y2, color)

  • (x1,y1) 为左上角坐标,(x2,y2) 为右下角坐标
    1. header('Content-type:image/jpeg');
    2. $res = imagecreatetruecolor(1000, 500);
    3. $red = imagecolorallocate($res, 255, 0, 0);
    4. $green = imagecolorallocate($res, 0, 255, 0);
    5. imagefill($res, 0, 0, $red);
    6. imagefilledrectangle($res, 100, 100, 300, 300, $green);
    7. imagejpeg($res);

绘制圆形

绘制空心圆形

  • imageEllipse(img_res,x,y,h,color)

绘制填充好的实心圆

  • imageFilledEllipse(img_res,x,y,w,h,color)

说明:

  • (x,y) 为圆心坐标。w 为宽度,h 为高度
    1. header('Content-type:image/jpeg');
    2. $res = imagecreatetruecolor(500, 500);
    3. $red = imagecolorallocate($res, 255, 0, 0);
    4. $green = imagecolorallocate($res, 0, 255, 0);
    5. imagefill($res, 0, 0, $red);
    6. imageellipse($res, 250, 250, 100, 100, $green);
    7. imagejpeg($res);

绘制线条

imageLine(img_res, x1, y1, x2, y2, color)

  • (x1, y1) 为起始点坐标
  • (x2, y2) 为结束点坐标
    1. $res = imagecreatetruecolor(500, 500);
    2. $red = imagecolorallocate($res, 255, 0, 0);
    3. $green = imagecolorallocate($res, 0, 255, 0);
    4. imagefill($res, 0, 0, $red);
    5. imageline($res, 0, 0, 499, 499, $green);
    6. imagepng($res);

绘制像素

bool imagesetpixel(resource $image, int $x, int $y, int $color)

  • (x, y) 为点坐标
    1. header('Content-type:image/jpeg');
    2. $res = imagecreatetruecolor(500, 500);
    3. $red = imagecolorallocate($res, 255, 0, 0);
    4. $green = imagecolorallocate($res, 0, 255, 0);
    5. imagefill($res, 0, 0, $red);
    6. for ($i = 0; $i < 600; $i++) {
    7. imagesetpixel($res, mt_rand(0, 500), mt_rand(0, 500), $green);
    8. }
    9. 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编码)
    1. header('Content-type:image/png');
    2. $res = imagecreatetruecolor(500, 500);
    3. $red = imagecolorallocate($res, 255, 0, 0);
    4. $green = imagecolorallocate($res, 0, 255, 0);
    5. imagefill($res, 0, 0, $red);
    6. $font = realpath('source.otf');
    7. imagettftext($res, 50, 0, 0, 50, $green, $font, 'houdunren.com');
    8. imagepng($res);
    9. 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 位置 |

文字在画布右上角显示

  1. $font = realpath('EBRIMA.TTF');
  2. $text = '0x208.cc';
  3. $size = 16;
  4. $box = imagettfbbox($size, 0, $font, $text);
  5. $width = $box[2] - $box[0];
  6. $height = $box[0] - $box[6];
  7. imagettftext($res, $size, 0, 500 - $width, $height, $green, $font, $text);

文字在画布中间显示

  1. ...
  2. imagettftext($res, $size, 0, 250 - $width / 2, 250 - $height / 2, $green, $font, $text);
  3. ...

外部图像

打开图像文件

  • 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 )

验证码

使用方法

  1. # 后台code.php
  2. include 'Captcha.php';
  3. $code = new Captcha(100, 30, 20);
  4. $code->make();
  5. # 前台
  6. <img src="code.php" alt="">

验证码类

  1. <?php
  2. class Captcha
  3. {
  4. protected $width;
  5. protected $height;
  6. protected $res;
  7. protected $len = 4;
  8. protected $font;
  9. protected $size;
  10. protected $code;
  11. public function __construct(int $width = 100, int $height = 30, $size = 20)
  12. {
  13. $this->width = $width;
  14. $this->height = $height;
  15. $this->font = realpath('EBRIMA.TTF');
  16. $this->size = $size;
  17. }
  18. public function make()
  19. {
  20. $res = imagecreatetruecolor($this->width, $this->height);
  21. imagefill($this->res = $res, 0, 0, imagecolorallocate($res, 200, 200, 200));
  22. $this->text();
  23. $this->line();
  24. $this->pix();
  25. $this->render();
  26. return $this->code;
  27. }
  28. protected function text()
  29. {
  30. $text = 'abcdefghigk123456789';
  31. for ($i = 0; $i < $this->len; $i++) {
  32. $x = $this->width / $this->len * $i;
  33. $box = imagettfbbox($this->size, 0, $this->font, $text[$i]);
  34. $this->code .= $code = strtoupper($text[mt_rand(0,strlen($text)-1)]);
  35. imagettftext(
  36. $this->res,
  37. $this->size,
  38. mt_rand(-20, 20),
  39. $x,
  40. $this->height / 2 + ($box[0] - $box[7]) / 2,
  41. $this->textColor(),
  42. $this->font,
  43. $code
  44. );
  45. }
  46. }
  47. protected function pix()
  48. {
  49. for ($i = 0; $i < 300; $i++) {
  50. imagesetpixel(
  51. $this->res,
  52. mt_rand(0, $this->width),
  53. mt_rand(0, $this->height),
  54. $this->color()
  55. );
  56. }
  57. }
  58. protected function line()
  59. {
  60. for ($i = 0; $i < 6; $i++) {
  61. //线条宽度
  62. imagesetthickness($this->res, mt_rand(1, 3));
  63. imageline(
  64. $this->res,
  65. mt_rand(0, $this->width),
  66. mt_rand(0, $this->height),
  67. mt_rand(0, $this->width),
  68. mt_rand(0, $this->height),
  69. $this->color()
  70. );
  71. }
  72. }
  73. protected function color()
  74. {
  75. return imagecolorallocate($this->res, mt_rand(100, 200), mt_rand(100, 200), mt_rand(100, 200));
  76. }
  77. protected function textColor()
  78. {
  79. return imagecolorallocate($this->res, mt_rand(50, 150), mt_rand(50, 150), mt_rand(50, 150));
  80. }
  81. protected function render()
  82. {
  83. header('Content-type:image/png');
  84. imagepng($this->res);
  85. }
  86. }

水印类

调用方式

  1. <?php
  2. include "Water.php";
  3. $water = new Water("logo.png");
  4. $water->make('sun.png', '2.png', 5);

水印类源码

  1. <?php
  2. class Water
  3. {
  4. //水印资源
  5. protected $water;
  6. //水印图片
  7. public function __construct(string $water)
  8. {
  9. $this->water = $water;
  10. }
  11. //入口方法
  12. public function make(string $image, string $filename = null, int $pos = 9)
  13. {
  14. $res = $this->resource($image);
  15. $water = $this->resource($this->water);
  16. $postion = $this->position($res, $water, $pos);
  17. imagecopy($res, $water, $postion['x'], $postion['y'], 0, 0, imagesx($water), imagesy($water));
  18. $this->showAction($image)($res, $filename ?: $image);
  19. }
  20. //获取资源对象
  21. protected function resource($image)
  22. {
  23. $info = getimagesize($image);
  24. $function = [1 => 'imagecreatefromgif', 2 => 'imagecreatefromjpeg', 3 => 'imagecreatefrompng'];
  25. $call = $function[$info[2]];
  26. return $call($image);
  27. }
  28. //根据类型输出图片
  29. protected function showAction(string $image)
  30. {
  31. $info = getimagesize($image);
  32. $function = [1 => 'imagegif', 2 => 'imagejpeg', 3 => 'imagepng'];
  33. return $function[$info[2]];
  34. }
  35. //位置
  36. protected function position($des, $res, int $pos)
  37. {
  38. $info = ['x' => 0, 'y' => 0];
  39. switch ($pos) {
  40. case 1:
  41. break;
  42. case 2:
  43. $info['x'] = (imagesx($des) - imagesx($res)) / 2;
  44. break;
  45. case 3:
  46. $info['x'] = (imagesx($des) - imagesx($res));
  47. break;
  48. case 4:
  49. $info['y'] = (imagesy($des) - imagesy($res)) / 2;
  50. break;
  51. case 5:
  52. $info['x'] = (imagesx($des) - imagesx($res)) / 2;
  53. $info['y'] = (imagesy($des) - imagesy($res)) / 2;
  54. break;
  55. }
  56. return $info;
  57. }
  58. }

缩略图

调用方式

  1. include 'Resize.php';
  2. $image = new Resize;
  3. $image->make('sun.png', '1.jpeg', 200, 200, 3);

缩略图类

  1. <?php
  2. class Resize
  3. {
  4. public function make(string $file, string $to = null, int $width = 200, int $height = 200, int $type = 3)
  5. {
  6. $image = $this->resource($file);
  7. $info = $this->size($width, $height, imagesx($image), imagesy($image), $type);
  8. $res = imagecreatetruecolor($info[0], $info[1]);
  9. imagecopyresampled($res, $image, 0, 0, 0, 0, $info[0], $info[1], $info[2], $info[3]);
  10. header('Content-type:image/jpeg');
  11. imagejpeg($res);
  12. }
  13. protected function size($rw, $rh, $iw, $ih, int $type)
  14. {
  15. switch ($type) {
  16. case 1:
  17. //固定宽度,高度自动
  18. $rh = $rw / $iw * $ih;
  19. break;
  20. case 2:
  21. //高度固定,宽度自动
  22. $rw = $rh / $ih * $iw;
  23. break;
  24. case 3:
  25. //固定宽度,高度裁切
  26. $ih = $iw / $rw * $rh;
  27. break;
  28. default:
  29. if (($iw / $rw) > ($ih / $rh)) {
  30. $iw = $ih / $rh * $rh;
  31. } else {
  32. $ih = $iw / $rw * $rw;
  33. }
  34. }
  35. return [$rw, $rh, $iw, $ih];
  36. }
  37. protected function resource(string $image)
  38. {
  39. if (!file_exists($image) || getimagesize($image) === false) {
  40. throw new Exception("file dont exists or it's not an image file");
  41. }
  42. $functions = [1 => 'imagecreatefromgif', 2 => 'imagecreatefromjpeg', 3 => 'imagecreatefrompng'];
  43. $info = getimagesize($image);
  44. $call = $functions[$info[2]];
  45. return $call($image);
  46. }
  47. }