Repository: php-imagine/Imagine (language: php)

Issue:
Saving Lossless Webp?
### Issue description

Since php 8.1 the php GD library supports the saving of images in the webp lossless format using the construct:
```
imagewebp($image, 'image.webp', IMG_WEBP_LOSSLESS);
```
where IMG_WEBP_LOSSLESS is a constant set to the value 101.

The `saveOrOutput` method in the GD\Image.php class has an explicit check (line 734) to prevent the value of the quality parameter exceeding the bounds 0-100.

How in this case then can lossless webp images be saved?


Discussion / hints:

Fix patch:
diff --git a/src/Gd/Image.php b/src/Gd/Image.php
index a27e31b3..6c9d21d6 100644
--- a/src/Gd/Image.php
+++ b/src/Gd/Image.php
@@ -730,7 +730,9 @@ private function finalizeOptions(Format $format, array $options)
                         $options['webp_quality'] = $options['quality'];
                     }
                 }
-                if (isset($options['webp_quality'])) {
+                if (!empty($options['webp_lossless'])) {
+                    $result[] = defined('IMG_WEBP_LOSSLESS') ? IMG_WEBP_LOSSLESS : 100;
+                } elseif (isset($options['webp_quality'])) {
                     if ($options['webp_quality'] < 0 || $options['webp_quality'] > 100) {
                         throw new InvalidArgumentException('webp_quality option should be an integer from 0 to 100');
                     }
diff --git a/src/Gmagick/Image.php b/src/Gmagick/Image.php
index a638796a..0ef17830 100644
--- a/src/Gmagick/Image.php
+++ b/src/Gmagick/Image.php
@@ -368,6 +368,13 @@ private function applyImageOptions(\Gmagick $image, array $options, $path)
                 if (isset($options['webp_quality'])) {
                     $image->setCompressionQuality($options['webp_quality']);
                 }
+                if (isset($options['webp_lossless'])) {
+                    if (method_exists($image, 'setimageoption')) {
+                        $image->setimageoption('webp', 'lossless', $options['webp_lossless'] ? 'true' : 'false');
+                    } elseif ($options['webp_lossless']) {
+                        $image->setCompressionQuality(100);
+                    }
+                }
                 break;
         }
         if (isset($options['resolution-units']) && isset($options['resolution-x']) && isset($options['resolution-y'])) {


Test patch:
diff --git a/tests/tests/Image/AbstractImageTest.php b/tests/tests/Image/AbstractImageTest.php
index 564f03a9..a4613437 100644
--- a/tests/tests/Image/AbstractImageTest.php
+++ b/tests/tests/Image/AbstractImageTest.php
@@ -1127,6 +1127,7 @@ public function imageCompressionQualityProvider()
             array(Format::ID_JPEG, array('jpeg_quality' => 0), array('jpeg_quality' => 100)),
             array(Format::ID_PNG, array('png_compression_level' => 9), array('png_compression_level' => 0)),
             array(Format::ID_WEBP, array('webp_quality' => 0), array('webp_quality' => 100)),
+            array(Format::ID_WEBP, array('webp_quality' => 0), array('webp_lossless' => true)),
             array(Format::ID_AVIF, array('avif_quality' => 0), array('avif_quality' => 100)),
             array(Format::ID_AVIF, array('avif_quality' => 0), array('avif_lossless' => true)),
             array(Format::ID_HEIC, array('heic_quality' => 0), array('heic_quality' => 100)),