libvips / php-vips

php binding for libvips
MIT License
618 stars 25 forks source link

webp not compressing properly in Debian Bookworm #235

Open binaryfire opened 9 months ago

binaryfire commented 9 months ago

Hi @jcupitt

I'm having some strange issues with generating webp images with php-vips on Debian bookworm. The output file sizes are very large compared to using cwebp. Here are the results from generating a 16px webp from a 1200x1200 jpg:

// php-vips (webp)

Image::thumbnail($inputPath, 16)
    ->writeToFile(base_path('test.webp'), ['Q' => 20, 'strip' => true, 'reduction_effort' => 4]);

File size: ~24kb

// cwebp

$command = [
            'cwebp',
            '-resize',
            16,
            0,
            '-q',
            20,
            $inputPath,
            '-o',
            base_path('test.webp'),
        ];

        $process = new Process($command);
        $process->run();

File size: 166 bytes (which is what I was expecting)

Even the jpg and png versions generated by php-vips are smaller than the webp version:

// php-vips (jpg)

$lqip = Image::thumbnail($inputPath, 16)
    ->writeToFile(base_path('test.jpg'), ['Q' => 20, 'strip' => true]);

File size: 620 bytes

// php-vips (png)

$lqip = Image::thumbnail($inputPath, 16)
    ->writeToFile(base_path('test.png'), ['Q' => 20, 'strip' => true]);

File size: 920 bytes

Any idea what might be happening? libvips and libwebp7 are both installed, and changing the Q value does change the file size (eg. 'Q' => 100 creates bigger files than 'Q' => 20). So I'm assuming webp is working.

The 16px images are saved as base64 and used as part of my LQIP system, so they need to be 100-200 bytes. I've switched over to cwebp for now but I'd like to get it working with php-vips if possible.

binaryfire commented 9 months ago

Did a couple more tests with larger output dimensions. webp definitely seems to be working, just not as efficiently as cwebp:

// php-vips (webp)

Image::thumbnail($inputPath, 1000)
    ->writeToFile(base_path('test.webp'), ['Q' => 20, 'strip' => true, 'reduction_effort' => 8]);

File size: 41kb

// cwebp

$command = [
            'cwebp',
            '-resize',
            1000,
            0,
            '-q',
            20,
            $inputPath,
            '-o',
            base_path('test.webp'),
        ];

        $process = new Process($command);
        $process->run();

File size: 24kb

jcupitt commented 9 months ago

Hello @binaryfire,

I had a go here. I made a test 16x16 pixel file like this:

$ vipsthumbnail nina.jpg x.png -s "16x16!" -o x.png
$ vipsheader x.png
x.png: 16x16 uchar, 3 bands, srgb, pngload

Then compressed with vips and cwebp:

$ cwebp x.png -o cwebp.webp -q 20
Saving file 'cwebp.webp'
File:      x.png
Dimension: 16 x 16
Output:    44 bytes Y-U-V-All-PSNR 99.00 99.00 99.00   99.00 dB
           (1.38 bpp)
block count:  intra4:          0  (0.00%)
              intra16:         1  (100.00%)
              skipped:         0  (0.00%)
bytes used:  header:              6  (13.6%)
             mode-partition:      3  (6.8%)
 Residuals bytes  |segment 1|segment 2|segment 3|segment 4|  total
    macroblocks:  |     100%|       0%|       0%|       0%|       1
      quantizer:  |      62 |      62 |      62 |      62 |
   filter level:  |      21 |      21 |      21 |      21 |
$ vips webpsave x.png vips.webp --Q 20 --strip
$ ls -l vips.webp cwebp.webp 
-rw-rw-r-- 1 john john 44 Feb 12 11:47 cwebp.webp
-rw-rw-r-- 1 john john 44 Feb 12 11:48 vips.webp

So both 44 bytes. This is libvips 8.15.2 on ubuntu 23.10 with libwebp 1.2.4.

binaryfire commented 9 months ago

Thanks for the info @jcupitt. I haven't tested using the CLI. Do you get the same results using Image::thumbnail?

jcupitt commented 9 months ago

I've not tested, but it's all the same functions underneath, so it should be the same, yes.

binaryfire commented 9 months ago

Same problem with the CLI in Debian Bookworm.

Original file: https://images.pexels.com/photos/813011/pexels-photo-813011.jpeg

Commands:

vipsthumbnail image.jpeg -s "16x16!" -o sm.jpeg
vips webpsave sm.jpeg vips.webp --Q 20 --strip
cwebp sm.jpeg -o cwebp.webp -q 20

Result:

image

This is the Docker image I'm using (it's the main php-cli image): https://hub.docker.com/r/library/php/tags?page=1&name=cli-bookworm. I've added the libvips and libvips-tools packages to the image - other than that it's stock standard.

binaryfire commented 9 months ago

@jcupitt Interesting - it's Debian-specific. Results in an Ubuntu 22.04 container:

image

Is it possible there's an issue with the Debian packages?

binaryfire commented 9 months ago

I've created a reproduction repository: https://github.com/binaryfire/vips-webp-debian-issue.

You just need to clone the repo and run:

./build-debian.sh
docker run --rm -it debian-vips /bin/bash
cd root
./test.sh

Then check out the generated files. This is test.sh

I didn't bother creating an Ubuntu Dockerfile since the same thing is working as expected there.

jcupitt commented 9 months ago

The debian libvips and libwebp might just be very old. They are extremely conservative.

binaryfire commented 9 months ago

Just checked the versions. I don't think that's the issue:

Debian Bookworm version:

image

Ubuntu 22.04 version:

image

Unless there was a webp bug in 8.14.1?

jcupitt commented 9 months ago

Ah the ChangeLog notes a fix in 8.14.2:

- fix `strip` parameter in webpsave [jcupitt]

So update libvips to fix this.