1

我想尽可能快地将作为字符串保存在变量中的图像转换为 WebP 格式,同时缩小较大的图像但不放大较小的图像。基本系统是带有 PHP 7.3 的 Debian 9.9。我尝试测量以下技术的速度:imagejpegimagewebp、 使用cwepphp-vips。我使用了以下代码:

$jpeg = function() use ($image) {
    $old_image = @imagecreatefromstring($image);
    $old_width = (int)@imagesx($old_image);
    $old_height = (int)@imagesy($old_image);
    $new_width = 1920;
    $new_width = min($old_width, $new_width);
    $ratio = $new_width / $old_width;
    $new_height = $old_height * $ratio;
    $new_image = imagecreatetruecolor($new_width, $new_height);
    imagecopyresampled($new_image, $old_image, 0, 0, 0, 0, $new_width, $new_height, $old_width, $old_height);
    ob_start();
    imagejpeg($new_image, NULL, 75);
    $image = ob_get_clean();
};
$webp = function() use ($image) {
    $old_image = @imagecreatefromstring($image);
    $old_width = (int)@imagesx($old_image);
    $old_height = (int)@imagesy($old_image);
    $new_width = 1920;
    $new_width = min($old_width, $new_width);
    $ratio = $new_width / $old_width;
    $new_height = $old_height * $ratio;
    $new_image = imagecreatetruecolor($new_width, $new_height);
    imagecopyresampled($new_image, $old_image, 0, 0, 0, 0, $new_width, $new_height, $old_width, $old_height);
    ob_start();
    imagewebp($new_image, NULL, 75);
    $image = ob_get_clean();
};
$convert = function(string $image, int $width, int $height) {
    $cmd = sprintf('cwebp -m 0 -q 75 -resize %d %d -o - -- -', $width, $height);
    $fd = [
        0 => [ 'pipe', 'r' ], // stdin is a pipe that the child will read from
        1 => [ 'pipe', 'w' ], // stdout is a pipe that the child will write to
        2 => [ 'pipe', 'w' ], // stderr is a pipe that the child will write to
    ];
    $process = proc_open($cmd, $fd, $pipes, NULL, NULL);
    if (is_resource($process)) {
        fwrite($pipes[0], $image);
        fclose($pipes[0]);
        $webp = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        $result = proc_close($process);
        if ($result === 0 && strlen($webp)) {
            return $webp;
        }
    }
    return FALSE;
};
$cwebp = function() use ($image, $convert) {
    $old_image = @imagecreatefromstring($image);
    $old_width = (int)@imagesx($old_image);
    $old_height = (int)@imagesy($old_image);
    $new_width = 1920;
    $new_width = min($old_width, $new_width);
    $ratio = $new_width / $old_width;
    $new_height = $old_height * $ratio;
    $image = $convert($image, $new_width, $new_height);
};
$vips = function() use ($image) {
    $image = Vips\Image::newFromBuffer($image);
    $old_width = (int)$image->get('width');
    $old_height = (int)$image->get('height');
    $new_width = 1920;
    $new_width = min($old_width, $new_width);
    $ratio = $new_width / $old_width;
    // $new_height = $old_height * $ratio;
    $image = $image->resize($ratio);
    $image = $image->writeToBuffer('.webp[Q=75]');
};

我在一个循环中调用了 , 和 10 次,运行时在几秒钟$jpeg()内是$webp()$cwebp()$vips()

JPEG: 0.65100622177124
WEBP: 1.4864070415497
CWEBP: 0.52562999725342
VIPS: 1.1211001873016

所以调用cwebpCLI 工具似乎是最快的方法,这令人惊讶。我已经读过很多次了,这vips是一个非常快的工具(大部分都比 快imagemagick),所以我想专注于vips.

谁能帮我优化$vips()以获得更好的性能?writeToBuffer()也许有一些resize()我不知道的选项。非常重要的是,所有操作都只在内存中工作,而无需从磁盘读取文件或将文件存储在磁盘上。

4

1 回答 1

7

为了速度,不要使用resize,使用thumbnail_buffer。它将打开和调整大小结合在一个操作中,因此它可以利用加载时收缩等功能。根据图像格式和大小,您可以获得巨大的加速。

您可以将 cwebp 设置与以下内容匹配:

$vips = function() use ($source_bytes) {
    $image = Vips\Image::thumbnail_buffer($source_bytes, 1920);
    $dest_bytes = $image->writeToBuffer('.webp', [
        'Q' => 75,
        'reduction-effort' => 0,
        'strip' => TRUE
    ]);
};

libvips 在直接 webp 压缩时似乎更慢。我试过:

$ time cwebp -m 0 -q 75 ~/pics/k2.jpg -o x.webp
real    0m0.102s
user    0m0.087s
sys 0m0.012s

匹配的 vips 命令将是:

$ time vips copy ~/pics/k2.jpg x.webp[Q=75,reduction-effort=0,strip]
real    0m0.144s
user    0m0.129s
sys 0m0.024s

你可以看到它可能慢了 30%。这里没有图像处理,只是调用 libjpeg 和 libwebp,所以 cwebp 必须使用 libvips 没有的一些 libwebp 保存优化。一年前它们以同样的速度运行——我应该再读cwebp.c一遍,看看有什么变化。

如果你也做一些处理,那么 libvips 会变得更快。我尝试使用 10,000 x 10,000 像素的图像并调整大小:

$ /usr/bin/time -F %M:%e cwebp -m 0 -q 75 ~/pics/wtc.jpg -resize 1920 1920 -o x.webp
618716:1.37

620mb 内存和 1.4s,对比:

$ /usr/bin/time -f %M:%e vipsthumbnail ~/pics/wtc.jpg -s 1920 -o x.webp[Q=75,reduction-effort=0,strip]
64024:1.08

64mb 内存和 1.1s。

所以 libvips 出来的速度更快,需要的内存更少,尽管 webp 压缩速度较慢,因为它可以快速调整大小。libvips 也在进行更高质量的调整大小(自适应 lanczos3),而不是 cwebp 的简单三次(我认为)。

于 2019-12-07T23:15:14.977 回答