如果没有图片,互联网将变得非常乏味。然而,为你的网站维护和处理成百上千的图片可能是一件令人头痛的事。随着你的网站设计的变化,你可能需要修改你的所有图像--例如,你可能需要将你的所有图像转换为灰度,或将它们的大小调整为原来的50%。你可能还想压缩或裁剪不同的图片。手动操作既费时又容易出错,但只要有一点编程知识就可以实现自动化。
在本教程中,你将了解到PHP中的GD(Graphic Draw)库。你将看到这个库是如何通过调整大小、裁剪、旋转或过滤来处理图像的。
什么是GD?
PHP能做的远不止是向访问者提供HTML。例如,它有处理图像的能力。不仅如此,你还可以从头开始创建你自己的图片,然后保存它们或将它们提供给用户。
使用GD 库(Graphic Draw 的缩写),PHP 可以处理几乎所有的基本图像处理需求。
设置
如果在Windows下工作,可以在php.ini中把php_gd2.dll文件作为一个扩展名。如果你使用的是XAMPP,你会在xampp/php/ext目录下找到php_gd2.dll文件。你也可以使用函数phpinfo(); ,检查GD是否安装在你的系统上。如果你滚动浏览结果输出,你会发现与下面类似的内容。

使用PHP GD创建图像
使用PHP操作图像的第一步是将其作为图像资源加载到内存中。这可以通过使用不同格式的函数来实现。所有这些函数都有非常相似的名字,所以它们很容易记住。
创建一个新的图像
如果没有想要处理的原始图像源,imagecreatetruecolor() 函数会有帮助。它接受两个整数参数:宽度和高度。如果一切按计划进行,它将返回一个图像资源。返回的图像资源基本上是一个具有指定宽度和高度的黑色图像。
加载一个图像文件
如果你打算操作已经存储在某个地方的图像,你将受益于使用imagecreatefromjpeg(),imagecreatefrompng(), 和imagecreatefromgif() 这样的函数。这些函数将用加载的图像文件的所有数据创建一个图像资源。这些函数接受一个单一的参数,指定你要加载的图像的位置,可以是一个URL,也可以是一个文件路径。
从一个字符串创建一个图像
GD库也允许你使用PHP中的imagecreatefromstring() 函数从一个字符串中创建图像。请记住,你必须在imagecreatefromstring() 之前对给定的字符串使用base64_decode() 。该函数可以自动检测图像类型是否为JPG、PNG、GIF或其他支持的格式。
旋转、缩放、裁剪和翻转图片
你可能想对一个图像资源进行的一些常见操作是旋转、缩放、裁剪和翻转。
旋转
你可以使用imagerotate() 函数来旋转你已经加载到脚本中的图像。它将以图像的中心作为旋转的中心,按照提供的角度旋转图像。角度是以浮动值提供的,PHP认为它是旋转的度数值。
有时,旋转后的图像与原始版本相比会有不同的尺寸。这意味着在旋转后会出现一个未覆盖的区域。imagerotate() 函数的第三个参数可以用来指定旋转后的空白区域的背景颜色。
缩放
使用GD库来缩放图像是非常容易的。你只需要把图像资源以及宽度和高度传给imagescale() 。如果你省略了高度,GD将把图像缩放到指定的宽度,同时保留长宽比。
你还可以指定缩放图像的模式。它可以设置为IMG_NEAREST_NEIGHBOUR,IMG_BILINEAR_FIXED,IMG_BICUBIC, 等等。你需要记住的一件重要事情是,这个函数返回一个新的缩放图像源,而不是修改原来的图像。
裁剪
你可以使用GD中的imagecrop() 函数裁剪任何图像资源。第一个参数是原始图像资源,第二个参数是一个关联数组,键为x,y,width, 和height ,指定裁剪窗口的位置和尺寸。
上面的蝴蝶图片是用以下代码裁剪的。
$im_php = imagecreatefromjpeg('path/to/image');
$size = min(imagesx($im_php), imagesy($im_php));
$im_php = imagecrop($im_php, ['x' => $size*0.4, 'y' => 0, 'width' => $size, 'height' => $size]);
$im_php = imagescale($im_php, 300);
基本上,我们将最小边的长度存储在$size 变量中。然后,这个变量被用来定义我们裁剪矩形的边界。最后,图像被缩小,使其只有300像素的宽度和长度。这样我们就得到了一个大小合适的正方形图像。
翻转图像
图像可以通过imageflip() 功能进行水平、垂直或双向翻转。它接受你想要翻转的图像资源作为第一个参数,翻转模式作为第二个参数。翻转模式可以设置为IMG_FLIP_HORIZONTAL 、IMG_FLIP_VERTICAL 、或IMG_FLIP_BOTH 。
上图中左上角的图像是原始图像。右上图是用IMG_FLIP_HORIZONTAL ,左下图是用IMG_FLIP_VERTICAL ,右下图是用IMG_FLIP_BOTH 。(乌鸦的图片来自Pixabay。)
将过滤器应用到图片上
GD还有一个非常有用的imagefilter() 功能,它可以对使用前面图片的功能加载的不同图片资源应用过滤器。这个函数可以接受各种参数,取决于你要应用的过滤器。
首先,指定图像资源和你要应用的过滤器的名称。你可以把它设置为文档中提到的12种预定义的过滤器类型之一。
IMG_FILTER_NEGATE:颠倒图像中的颜色IMG_FILTER_GRAYSCALE:从图像中去除颜色IMG_FILTER_BRIGHTNESS:使图像更亮或更暗IMG_FILTER_CONTRAST增加图像的对比度IMG_FILTER_COLORIZE将图像染成选定的颜色IMG_FILTER_EDGEDETECT突出图像的边缘:突出图像的边缘IMG_FILTER_EMBOSS边缘检测:类似于边缘检测,但给每个边缘一个凸起的外观IMG_FILTER_GAUSSIAN_BLUR高斯法:用高斯法模糊图像IMG_FILTER_SELECTIVE_BLUR虚化:使用选择性方法虚化图像。IMG_FILTER_MEAN_REMOVAL创建一个风格化的图像的效果IMG_FILTER_SMOOTH使图像中的锯齿状边缘变得平滑IMG_FILTER_PIXELATE使图像看起来有像素感
有些过滤器,如NEGATE 、GRAYSCALE 、EDGE_DETECT 、EMBOSS ,不需要任何额外的数据。其他过滤器,如BRIGHTNESS,CONTRAST 和SMOOTH ,可以接受一个额外的参数,指定最终图像的亮度、对比度或平滑度的数量。PIXELATE 参数允许你指定两个额外的参数:块大小以及像素化的模式。最后,COLORIZE 过滤器接受四个参数,这些参数决定了红、绿、蓝分量以及α通道的值。
左上角的图像是原始图像。右上角的图像是用COLORIZE 滤波器制作的,左下角的图像是用GRAYSCALE 滤波器制作的,右下角的图像是用BRIGHTNESS 。(这张蝴蝶图片是在Pixabay找到的)。
其他有用的图像处理功能
你还应该知道其他一些常用的GD函数,它们时常会派上用场。
获取图像尺寸
你可以使用imagesx() 和imagesy() 函数来确定一个图像资源的宽度和高度。
另一个名为getimagesize() 的函数也可以用来获取图像的宽度和高度以及它的类型。这个函数返回一个数组,其中的元素指定了图像的宽度、高度和格式。数组的前两个元素描述宽度和高度,第三个元素包含一个指定文件格式的常数:IMAGETYPE_PNG,IMAGETYPE_GIF, 等等。
保存一个图像
一旦你对图像做了所有想要的改变,你很可能想把它输出到浏览器或保存为一个文件。在这两种情况下,你都必须使用GD的一个输出函数,如 imagejpeg(), imagepng(),或 imagegif().你将把你的图像资源传递给这些输出函数之一,如果你想把图像保存到一个文件,你也要指定一个文件名。你还可以根据图像的类型,使用第三个可选参数来控制输出图像的质量。
获取和设置特定像素的颜色
在PHP中,有多种函数可以用来获取或设置图像中特定位置的单个像素的颜色。第一步是用imagecreatefrompng() 等函数创建一个图像资源。
之后,可以用函数imagecolorat($image, $x, $y) 来获取给定像素的颜色索引。像素的位置由函数中的第二个和第三个参数决定。如果这个函数是在真彩色图像上调用,你将得到像素的RGB值,是一个整数。现在,你可以使用位移和屏蔽来获得不同的颜色成分,或者使用另一个内置函数imagecolorsforindex($image, $color) 。
任何特定位置的像素的颜色都可以用imagesetpixel($image, $x, $y, $color) 函数来设置。
用PHP替换图片中的颜色
使用上面学到的概念,你可以在PHP中很容易地用另一种颜色来替换一个颜色。结果的质量会因图像的不同而不同。一般来说,颜色的变化越少意味着替换效果越好。使用这种方法可以非常有效地替换纯色。让我们写一些代码来替换以下图片中的颜色。

<?php
$filename = 'fancy_name.png'
$im_php = imagecreatefrompng($filename);
$origin_color = imagecolorsforindex($im_php, imagecolorat($im_php, 0, 0));
$dark_red = imagecolorallocate($im_php, 100, 0, 30);
list($width, $height, $type, $attr) = getimagesize($filename);
for($x = 0; $x <= $width - 1; $x++) {
for($y = 0; $y <= $height - 1; $y++) {
$index_color = imagecolorsforindex($im_php, imagecolorat($im_php, $x, $y));
if($origin_color == $index_color) {
imagesetpixel($im_php, $x, $y, $dark_red);
}
}
}
imagepng($im_php, 'fancy_name_red.png');
?>
上面的代码使用上一节中的函数来获取和设置颜色值。你应该注意到,我们正在做一个精确的颜色匹配。这可能会导致一些假象,因为像素在边界附近的颜色可能略有不同。在做精确匹配时,我们也可以避免对imagecolorsforindex() 函数的调用。然而,有了独立的颜色组件,你就可以在系统中引入一些宽容度,在某些情况下提供更好的结果。这里是最终的图像,有精确的颜色比较和替换。

调整一个目录中所有图片的大小
让我们应用到目前为止我们所获得的知识来做一些实际的事情。在本节中,我们将调整一个特定目录中所有JPEG图像的大小,使其宽度为640像素。高度将根据原始图像的尺寸自动计算。
我们将把调整后的图像保存在一个名为 "调整"的新文件夹中。在这种情况下,所有的原始图像都有相同的尺寸,但代码将在具有不同尺寸和长宽比的图像上正常工作。
$directory = 'Nature/';
$images = glob($directory."*.jpg");
foreach($images as $image) {
$im_php = imagecreatefromjpeg($image);
$im_php = imagescale($im_php, 640);
$new_height = imagesy($im_php);
$new_name = str_replace('-1920x1080', '-640x'.$new_height, basename($image));
imagejpeg($im_php, $directory.'Resized/'.$new_name);
}
在上面的代码中,我们首先使用glob() ,在名为Nature的目录中找到所有扩展名为**.jpg**的图片。这些图片文件被存储在一个数组中,我们逐一循环。
由于我们要调整大小的所有图片都是JPEG格式的,我们使用imagecreatefromjpeg() 函数将它们加载到脚本中。然后,imagescale() 函数被用来调整图像的大小,使其达到一个特定的宽度--在我们的例子中是640像素。我们没有指定一个固定的高度,所以高度将被自动计算。
每个原始图像文件都在文件名上附加了**-1920x1080**,以表明其尺寸。我们在原始文件名上使用str_replace() ,用新的图像尺寸替换**-1920X1080**。
最后,我们将调整后的图像保存在一个名为 "**调整 "**的文件夹中,并加上新的文件名。你也可以向imagejpeg() 函数传递第三个参数,以设置保存的图像文件的质量。如果省略第三个参数,图像将以75的默认质量保存。
对一个目录中的每张图片应用灰度和对比度过滤器
这一次,我们将对目录中的每张图片应用两种不同的滤镜,并将最终结果保存在不同的目录中,而不对文件名做任何修改。让我们深入了解代码,我将在后面解释每个函数的作用。
$directory = 'Nature/';
$images = glob($directory."*.jpg");
foreach($images as $image) {
$im_php = imagecreatefromjpeg($image);
imagefilter($im_php, IMG_FILTER_GRAYSCALE);
imagefilter($im_php, IMG_FILTER_CONTRAST, -25);
$new_name = basename($image);
imagejpeg($im_php, $directory.'Grayscale/'.$new_name);
}
正如你所看到的,我们从Nature目录中加载图片,就像我们对前面的例子所做的那样。然而,这次我们将使用imagefilter() 函数来对加载的图像资源进行过滤。
请注意,imagefilter() 修改了原始图像,并根据操作的成功或失败返回TRUE 或FALSE 。这与我们在上一节中使用的imagescale() 函数不同,后者返回的是缩放的图像资源。
另一个需要记住的重要事情是,对比度过滤器接受-100到100的数值。负值意味着更多的对比度,而正值则意味着更少的对比度。这与一些人可能期望的情况正好相反。一个0的值将使图像保持不变。
另一方面,亮度过滤器的最小和最大限制是-255和255。在这种情况下,负值意味着最小亮度,而正值意味着最大亮度。
我们使用basename() 函数从文件路径中获取文件名,然后使用imagejpeg() 函数保存图像。
最后的思考
本教程的目的是让你熟悉PHP中的GD库,并告诉你如何使用所有这些函数来使你的生活更轻松。你可以用本教程末尾的例子作为指导,编写你自己的图像处理脚本。例如,你可以通过使用imagesx() 函数来确定图像的宽度,只有当它的宽度超过一个给定的限制时,才可以调整其大小。
所有这些函数开辟了很多可能性,使图像处理更容易,最终为你节省大量时间。如果你有任何与本教程有关的问题,请在评论中告诉我。