简介
Laravel 提供了一套流畅的图像处理 API,使你能够使用框架中随处可见的富有表现力的约定,对图像进行缩放、裁剪、编码和存储。Laravel 的图像功能由 Intervention Image 提供支持,并兼容 GD 和 Imagick PHP 扩展。
该图像 API 在处理已上传的文件、存储在 Laravel 文件系统磁盘 上的文件、本地文件、远程 URL 或原始图像字节时非常有用:
use Illuminate\Support\Facades\Image;
$path = Image::fromStorage('avatars/photo.jpg', 'public')
->cover(400, 400)
->toWebp()
->quality(80)
->storePublicly('avatars', 'public'); 图像处理对 CPU 和内存的消耗较大。建议将大型图像处理任务放到 队列任务 中执行,而不是在接受上传请求的 HTTP 请求中进行处理。
安装
在使用 Laravel 的图像处理功能之前,请通过 Composer 安装 Intervention Image 包:
composer require intervention/image:^4.0你还需要确保 PHP 环境安装了 GD 或 Imagick 扩展,具体取决于你的应用程序将要使用的驱动。
配置
Laravel 的图像配置文件位于 config/images.php。如果你的应用程序没有 images 配置文件,可以使用 config:publish Artisan 命令发布该文件:
php artisan config:publish images图像配置文件允许你指定应用程序的默认图像驱动。你也可以使用 IMAGE_DRIVER 环境变量来指定默认驱动。支持的驱动有 gd 和 imagick:
IMAGE_DRIVER=imagick读取图像
Image 门面(Facade)提供了多种从常见来源读取图像的方法。图像内容采用懒加载机制,因此通常只有在对图像进行处理或请求其字节内容时,才会读取数据源。
已上传的文件
你可以使用 image 方法从传入的请求中获取已上传的图像。该方法会返回上传文件对应的 Illuminate\Image\Image 实例,如果文件不存在,则返回 null:
use Illuminate\Http\Request;
Route::post('/avatar', function (Request $request) {
$request->validate(['avatar' => ['required', 'image']]);
$path = $request->image('avatar')
->cover(400, 400)
->toWebp()
->storePublicly('avatars', 'public');
// ...
});或者,你也可以使用 fromUpload 方法,基于 Illuminate\Http\UploadedFile 实例创建图像实例:
use Illuminate\Support\Facades\Image;
$image = Image::fromUpload($request->file('avatar'));当图像是通过上传的文件创建时,你可以使用 file 方法获取底层的上传文件:
$file = $image->file();存储文件
你可以使用 fromStorage 方法,从应用程序的某个 文件系统磁盘 上存储的文件创建图像实例。第一个参数是文件路径,第二个参数是磁盘名称:
use Illuminate\Support\Facades\Image;
$image = Image::fromStorage('avatars/photo.jpg', disk: 'public');你还可以使用 image 方法,直接从文件系统磁盘实例创建图像实例:
use Illuminate\Support\Facades\Storage;
$image = Storage::disk('public')->image('avatars/photo.jpg');其他来源
Image 门面(Facade)还提供了一些方法,可基于原始字节、本地文件路径、远程 URL 以及 Base64 编码字符串创建图像实例:
use Illuminate\Support\Facades\Image;
$image = Image::fromBytes($contents);
$image = Image::fromBase64($base64);
$image = Image::fromPath(storage_path('app/avatars/photo.jpg'));
$image = Image::fromUrl('https://example.com/photo.jpg');处理图像
图像实例是不可变的。每个处理方法都会返回一个新的图像实例,并将转换操作追加到其处理流水线中,从而支持方法的流畅链式调用:
$image = $request->image('avatar')
->orient()
->cover(400, 400)
->sharpen(10);转换操作将按照添加到图像流水线的顺序进行处理,图像只会在最后进行一次编码。
缩放图像
resize 方法可将图像缩放为指定尺寸。你可以同时提供宽度和高度,也可以使用命名参数只提供其中一个尺寸:
$image = $image->resize(800, 600);
$image = $image->resize(width: 800);
$image = $image->resize(height: 600);scale 方法会按比例缩小图像,使其适配给定的尺寸范围。该方法永远不会放大图像:
$image = $image->scale(800, 600);
$image = $image->scale(width: 800);
$image = $image->scale(height: 600);cover 方法会对图像进行缩放和裁剪,使其完全覆盖指定尺寸:
$image = $image->cover(400, 400);contain 方法会缩放图像,使其在保留完整图像的前提下适配给定尺寸。如有必要,空白区域将使用可选的背景色进行填充:
$image = $image->contain(400, 400);
$image = $image->contain(400, 400, '#ffffff');
$image = $image->contain(400, 400, 'dominant');你可以将 dominant 指定为背景色,使用图像的主色调填充空白区域。
你可以使用 crop 方法裁剪图像。前两个参数是所需的宽度和高度,可选的第三和第四个参数用于指定裁剪的 x 和 y 坐标:
$image = $image->crop(300, 200);
$image = $image->crop(300, 200, x: 50, y: 25);其他转换
Laravel 还提供了多种额外的图像转换方法:
$image = $image->orient();
$image = $image->rotate(90);
$image = $image->rotate(90, '#ffffff');
$image = $image->rotate(90, 'dominant');
$image = $image->blur(5);
$image = $image->grayscale();
$image = $image->sharpen(10);
$image = $image->flipVertically();
$image = $image->flipHorizontally();orient 方法会根据图像的 EXIF 方向数据旋转图像。rotate 方法会按给定角度顺时针旋转图像,并支持可选的背景色参数。blur 和 sharpen 方法接受 0 到 100 之间的数值。
条件转换
图像实例支持 Laravel 的 Conditionable 特性,允许你使用 when 和 unless 方法有条件地应用转换操作:
$image = $request->image('avatar')
->when($request->boolean('crop'), fn ($image) => $image->cover(400, 400))
->unless($request->boolean('preserve_format'), fn ($image) => $image->toWebp());编码图像
默认情况下,处理后的图像会使用其原始格式进行编码。不过,你可以在获取或存储图像之前,将其转换为其他支持的格式:
$image = $image->toWebp();
$image = $image->toJpg();
$image = $image->toJpeg();
$image = $image->toPng();
$image = $image->toGif();
$image = $image->toAvif();
$image = $image->toBmp();你可以使用 quality 方法设置输出质量。质量值会被限制在 1 到 100 之间:
$image = $image->toWebp()->quality(80);optimize 方法是一个便捷的快捷方式,用于将图像转换为指定格式并设置其质量。默认情况下,图像会被优化为质量为 70 的 WebP 图像:
$image = $image->optimize();
$image = $image->optimize(format: 'jpg', quality: 85);你可以将处理后的图像内容作为字节字符串、Base64 编码字符串或数据 URI 获取:
$bytes = $image->toBytes();
$base64 = $image->toBase64();
$dataUri = $image->toDataUri();图像实例也可以转换为字符串,以获取数据 URI:
$dataUri = (string) $image;存储图像
store 方法会将处理后的图像存储到应用程序的某个文件系统磁盘中。与上传文件一样,Laravel 会生成一个唯一的文件名,并返回存储路径。第二个参数可用于指定磁盘:
$path = $request->image('avatar')
->cover(400, 400)
->store(path: 'avatars');
$path = $request->image('avatar')
->cover(400, 400)
->store(path: 'avatars', disk: 's3');您可以使用 storeAs 方法指定存储文件名:
$path = $request->image('avatar')
->cover(400, 400)
->storeAs(path: 'avatars', name: 'avatar.jpg', disk: 'public');storePublicly 和 storePubliclyAs 方法以 public 可见性存储图像:
$path = $request->image('avatar')
->cover(400, 400)
->storePublicly(path: 'avatars', disk: 'public');
$path = $request->image('avatar')
->cover(400, 400)
->storePubliclyAs(path: 'avatars', name: 'avatar.webp', disk: 'public');如果图像无法存储,存储方法将返回 false。
检查图像
您可以使用以下方法获取图像的 MIME 类型、扩展名、尺寸、宽度、高度和主色调:
$mimeType = $image->mimeType();
$extension = $image->extension();
[$width, $height] = $image->dimensions();
$width = $image->width();
$height = $image->height();
$dominantColor = $image->dominantColor();这些方法作用于处理后的图像。例如,在调用 cover(400, 400) 之后调用 width 将返回 400。
图像驱动程序
自定义图像驱动程序
Laravel 的图像管理器扩展了 Laravel 的基础类 Illuminate\Support\Manager。这意味着您可以使用图像管理器和 Image 门面上可用的 extend 方法注册自定义图像驱动程序。
自定义图像驱动程序应实现 Illuminate\Contracts\Image\Driver 接口。process 方法接收原始图像内容和应应用于图像的有序 Illuminate\Image\ImagePipeline,并应返回处理后的图像字节。dimensions 方法应返回图像的宽度和高度,而 dominantColor 方法应返回图像的平均颜色(十六进制字符串):
<?php
namespace App\Images;
use Illuminate\Contracts\Image\Driver;
use Illuminate\Image\ImagePipeline;
class VipsDriver implements Driver
{
/**
* 使用指定的管道处理给定的图像内容。
*/
public function process(string $contents, ImagePipeline $pipeline): string
{
// Apply the pipeline's transformations and output options...
return $contents;
}
/**
* 获取给定图像内容的尺寸。
*/
public function dimensions(string $contents): array
{
// Read the image's width and height...
return [0, 0];
}
/**
* 获取图像的主(平均)颜色,以十六进制字符串形式返回。
*/
public function dominantColor(string $contents): string
{
// Calculate the image's average color...
return '#000000';
}
/**
* 注册转换处理程序。
*/
public function transformUsing(string $transformation, callable $callback): static
{
// Store the handler so it may be applied while processing the pipeline...
return $this;
}
} 为了更好地理解如何实现自定义图像驱动程序,您可以查看框架内置的 Illuminate\Image\Drivers\InterventionDriver 类。
实现自定义驱动程序后,您可以使用 Image 门面的 extend 方法进行注册。通常,这应在服务提供者的 boot 方法中完成:
use App\Images\VipsDriver;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Image;
/**
* 启动任何应用程序服务。
*/
public function boot(): void
{
Image::extend('vips', function (Application $app) {
return new VipsDriver;
});
}注册驱动程序后,您可以使用 using 方法为特定图像指定该驱动程序:
$image = $request->image('avatar')
->using('vips')
->cover(400, 400);您也可以在应用程序的 config/images.php 配置文件中通过 default 选项,或使用 IMAGE_DRIVER 环境变量,将自定义驱动程序配置为应用程序的默认图像驱动程序:
IMAGE_DRIVER=vips自定义转换
应用程序和包可以通过创建一个实现 Illuminate\Contracts\Image\Transformation 契约的类来定义自定义转换。然后,可以使用 transform 方法将自定义转换添加到图像管道中:
<?php
namespace App\Images\Transformations;
use Illuminate\Contracts\Image\Transformation;
class Pixelate implements Transformation
{
public function __construct(
public readonly int $size,
) {
//
}
}接下来,使用 Image 门面的 transformUsing 方法为转换和驱动程序注册处理程序。通常,这应在服务提供者的 boot 方法中完成:
use App\Images\Transformations\Pixelate;
use Illuminate\Support\Facades\Image;
use Intervention\Image\Interfaces\ImageInterface;
Image::transformUsing('gd', Pixelate::class, function (ImageInterface $image, Pixelate $transformation) {
return $image->pixelate($transformation->size);
});转换处理程序注册完成后,您可以对图像应用该转换:
use App\Images\Transformations\Pixelate;
$image = $request->image('avatar')
->transform(new Pixelate(12))
->store('avatars');