From ec06c23f77932aaf905946cf43cea1a784e77398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Auswo=CC=88ger?= Date: Sat, 13 Feb 2021 22:05:10 +0100 Subject: [PATCH 1/3] Support AVIF and HEIC in Imagick driver --- src/Imagick/Image.php | 19 ++++++++++++++ tests/fixtures/avif-image.avif | Bin 0 -> 278 bytes tests/fixtures/heic-image.heic | Bin 0 -> 400 bytes tests/tests/Gd/ImageTest.php | 3 +++ tests/tests/Gd/ImagineTest.php | 20 +++++++++++++++ tests/tests/Gmagick/ImageTest.php | 4 +-- tests/tests/Gmagick/ImagineTest.php | 30 ++++++++++++++++++++++ tests/tests/Image/AbstractImageTest.php | 4 +++ tests/tests/Image/AbstractImagineTest.php | 28 ++++++++++++++++++++ tests/tests/Imagick/ImageTest.php | 4 +-- tests/tests/Imagick/ImagineTest.php | 28 ++++++++++++++++++++ 11 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 tests/fixtures/avif-image.avif create mode 100644 tests/fixtures/heic-image.heic diff --git a/src/Imagick/Image.php b/src/Imagick/Image.php index 9e62fcb2b..277c963ec 100644 --- a/src/Imagick/Image.php +++ b/src/Imagick/Image.php @@ -830,6 +830,23 @@ private function applyImageOptions(\Imagick $image, array $options, $path) $image->setOption('webp:lossless', $options['webp_lossless']); } break; + case 'avif': + case 'heic': + if (!isset($options[$format . '_quality'])) { + if (isset($options['quality'])) { + $options[$format . '_quality'] = $options['quality']; + } + } + if (isset($options[$format . '_quality'])) { + $options[$format . '_quality'] = max(1, min(99, $options[$format . '_quality'])); + $image->setimagecompressionquality($options[$format . '_quality']); + $image->setcompressionquality($options[$format . '_quality']); + } + if (!empty($options[$format . '_lossless'])) { + $image->setimagecompressionquality(100); + $image->setcompressionquality(100); + } + break; } if (isset($options['resolution-units']) && isset($options['resolution-x']) && isset($options['resolution-y'])) { if (empty($options['resampling-filter'])) { @@ -940,6 +957,8 @@ private function getMimeType($format) 'wbmp' => 'image/vnd.wap.wbmp', 'xbm' => 'image/xbm', 'webp' => 'image/webp', + 'avif' => 'image/avif', + 'heic' => 'image/heic', 'bmp' => 'image/bmp', ); diff --git a/tests/fixtures/avif-image.avif b/tests/fixtures/avif-image.avif new file mode 100644 index 0000000000000000000000000000000000000000..9ef0de4db18e022be727c0f6cf3ecba77967e007 GIT binary patch literal 278 zcmXv}%?`mp5T2??2tD`<2M5H>0aq8nOE_+}ZA{W_H??WFsWUo(IJo(?^qcH{ zKQqbf644+u7cDXl39zgkpJYVex1Ou!wPL}@IeGgVNvE25^zmb<*wgrqK? vbYKPG|4*N_D!+htxcSXRXQq5%+SI5IhWFPociipDYa{Pc)p?wQ_jvvVxSuWX literal 0 HcmV?d00001 diff --git a/tests/fixtures/heic-image.heic b/tests/fixtures/heic-image.heic new file mode 100644 index 0000000000000000000000000000000000000000..dabe4826511030b5e78cb21b6bfa540c8adeef1c GIT binary patch literal 400 zcmZQzV30^FsVvAy%}izhg51nBLkOGEAvd)o5hMl#iWw<6MGz(fLqTS835*S+`3f>i za={!%AgPp@lMgn|#esnl2!Vhx0YU?r20*NwnVFXc5(kTl0y(KnP+mq^vLT3hAhV#T z07x&&EJ)4=(q%viXGUg_5Cq75VEFU*#}5Vuer5%rF%k}pJdFSUgA_0`OaKu;B)5yn zK@lja>BI=uiX^kZq;Yxqv{#;*>vA|iN+E=U5>Pd}3**6}4N49`dqgse3sNEWF{A)# z5EdxNtjGk3F>`PLbuox#7UaT03g}(tMy6(l literal 0 HcmV?d00001 diff --git a/tests/tests/Gd/ImageTest.php b/tests/tests/Gd/ImageTest.php index be6810fdd..e605c3c3b 100644 --- a/tests/tests/Gd/ImageTest.php +++ b/tests/tests/Gd/ImageTest.php @@ -193,6 +193,9 @@ public function testSaveCompressionQuality($format, array $smallSizeOptions, arr if ($format === 'webp' && !function_exists('imagewebp')) { $this->markTestSkipped('GD webp support is not enabled'); } + if ($format === 'avif' || $format === 'heic') { + $this->markTestSkipped('GD does not support ' . strtoupper($format)); + } return parent::testSaveCompressionQuality($format, $smallSizeOptions, $bigSizeOptions); } diff --git a/tests/tests/Gd/ImagineTest.php b/tests/tests/Gd/ImagineTest.php index 94b226614..c91160931 100644 --- a/tests/tests/Gd/ImagineTest.php +++ b/tests/tests/Gd/ImagineTest.php @@ -47,6 +47,26 @@ public function testShouldOpenAWebPImage() return parent::testShouldOpenAWebPImage(); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImagineTest::testShouldOpenAAvifImage() + */ + public function testShouldOpenAAvifImage() + { + $this->markTestSkipped('GD does not support AVIF'); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImagineTest::testShouldOpenAHeicImage() + */ + public function testShouldOpenAHeicImage() + { + $this->markTestSkipped('GD does not support HEIC'); + } + /** * {@inheritdoc} * diff --git a/tests/tests/Gmagick/ImageTest.php b/tests/tests/Gmagick/ImageTest.php index 80e1cd92f..9c2277947 100644 --- a/tests/tests/Gmagick/ImageTest.php +++ b/tests/tests/Gmagick/ImageTest.php @@ -145,8 +145,8 @@ public function pasteWithAlphaProvider() public function testSaveCompressionQuality($format, array $smallSizeOptions, array $bigSizeOptions) { $gmagick = new \Gmagick(); - if ($format === 'webp' && !in_array('WEBP', $gmagick->queryformats('WEBP'), true)) { - $this->markTestSkipped('Gmagick webp support is not enabled'); + if (in_array($format, array('webp', 'avif', 'heic'), true) && !in_array(strtoupper($format), $gmagick->queryformats(strtoupper($format)), true)) { + $this->markTestSkipped('Gmagick ' . $format . ' support is not enabled'); } return parent::testSaveCompressionQuality($format, $smallSizeOptions, $bigSizeOptions); diff --git a/tests/tests/Gmagick/ImagineTest.php b/tests/tests/Gmagick/ImagineTest.php index b7c6ac8ac..9c1628911 100644 --- a/tests/tests/Gmagick/ImagineTest.php +++ b/tests/tests/Gmagick/ImagineTest.php @@ -60,6 +60,36 @@ public function testShouldOpenAWebPImage() return parent::testShouldOpenAWebPImage(); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImagineTest::testShouldOpenAAvifImage() + */ + public function testShouldOpenAAvifImage() + { + $gmagick = new \Gmagick(); + if (!in_array('AVIF', $gmagick->queryformats('AVIF'), true)) { + $this->markTestSkipped('Gmagick AVIF support is not enabled'); + } + + return parent::testShouldOpenAAvifImage(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImagineTest::testShouldOpenAHeicImage() + */ + public function testShouldOpenAHeicImage() + { + $gmagick = new \Gmagick(); + if (!in_array('HEIC', $gmagick->queryformats('HEIC'), true)) { + $this->markTestSkipped('Gmagick HEIC support is not enabled'); + } + + return parent::testShouldOpenAHeicImage(); + } + /** * {@inheritdoc} * diff --git a/tests/tests/Image/AbstractImageTest.php b/tests/tests/Image/AbstractImageTest.php index 46e7f0899..5e68015fd 100644 --- a/tests/tests/Image/AbstractImageTest.php +++ b/tests/tests/Image/AbstractImageTest.php @@ -981,6 +981,10 @@ public function imageCompressionQualityProvider() array('jpg', array('jpeg_quality' => 0), array('jpeg_quality' => 100)), array('png', array('png_compression_level' => 9), array('png_compression_level' => 0)), array('webp', array('webp_quality' => 0), array('webp_quality' => 100)), + array('avif', array('avif_quality' => 0), array('avif_quality' => 100)), + array('avif', array('avif_quality' => 0), array('avif_lossless' => true)), + array('heic', array('heic_quality' => 0), array('heic_quality' => 100)), + array('heic', array('heic_quality' => 0), array('heic_lossless' => true)), ); } diff --git a/tests/tests/Image/AbstractImagineTest.php b/tests/tests/Image/AbstractImagineTest.php index eae285ff4..2329de78e 100644 --- a/tests/tests/Image/AbstractImagineTest.php +++ b/tests/tests/Image/AbstractImagineTest.php @@ -61,6 +61,34 @@ public function testShouldOpenAWebPImage() $this->assertEquals(realpath($source), $metadata['filepath']); } + public function testShouldOpenAAvifImage() + { + $source = IMAGINE_TEST_FIXTURESFOLDER . '/avif-image.avif'; + $factory = $this->getImagine(); + $image = $factory->open($source); + $size = $image->getSize(); + $this->assertInstanceOf('Imagine\Image\ImageInterface', $image); + $this->assertEquals(100, $size->getWidth()); + $this->assertEquals(100, $size->getHeight()); + $metadata = $image->metadata(); + $this->assertEquals($source, $metadata['uri']); + $this->assertEquals(realpath($source), $metadata['filepath']); + } + + public function testShouldOpenAHeicImage() + { + $source = IMAGINE_TEST_FIXTURESFOLDER . '/heic-image.heic'; + $factory = $this->getImagine(); + $image = $factory->open($source); + $size = $image->getSize(); + $this->assertInstanceOf('Imagine\Image\ImageInterface', $image); + $this->assertEquals(100, $size->getWidth()); + $this->assertEquals(100, $size->getHeight()); + $metadata = $image->metadata(); + $this->assertEquals($source, $metadata['uri']); + $this->assertEquals(realpath($source), $metadata['filepath']); + } + public function testShouldOpenAnSplFileResource() { $source = IMAGINE_TEST_FIXTURESFOLDER . '/google.png'; diff --git a/tests/tests/Imagick/ImageTest.php b/tests/tests/Imagick/ImageTest.php index ab1cb6ed6..8075c9d16 100644 --- a/tests/tests/Imagick/ImageTest.php +++ b/tests/tests/Imagick/ImageTest.php @@ -172,8 +172,8 @@ public function testOptimize() */ public function testSaveCompressionQuality($format, array $smallSizeOptions, array $bigSizeOptions) { - if ($format === 'webp' && !in_array('WEBP', \Imagick::queryFormats('WEBP'), true)) { - $this->markTestSkipped('Imagick WebP support is not enabled'); + if (in_array($format, array('webp', 'avif', 'heic'), true) && !in_array(strtoupper($format), \Imagick::queryFormats(strtoupper($format)), true)) { + $this->markTestSkipped('Imagick ' . $format . ' support is not enabled'); } return parent::testSaveCompressionQuality($format, $smallSizeOptions, $bigSizeOptions); diff --git a/tests/tests/Imagick/ImagineTest.php b/tests/tests/Imagick/ImagineTest.php index d1a68e385..7bd6509a2 100644 --- a/tests/tests/Imagick/ImagineTest.php +++ b/tests/tests/Imagick/ImagineTest.php @@ -47,6 +47,34 @@ public function testShouldOpenAWebPImage() return parent::testShouldOpenAWebPImage(); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImagineTest::testShouldOpenAAvifImage() + */ + public function testShouldOpenAAvifImage() + { + if (!in_array('AVIF', \Imagick::queryFormats('AVIF'), true)) { + $this->markTestSkipped('Imagick AVIF support is not enabled'); + } + + return parent::testShouldOpenAAvifImage(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImagineTest::testShouldOpenAHeicImage() + */ + public function testShouldOpenAHeicImage() + { + if (!in_array('HEIC', \Imagick::queryFormats('HEIC'), true)) { + $this->markTestSkipped('Imagick HEIC support is not enabled'); + } + + return parent::testShouldOpenAHeicImage(); + } + /** * {@inheritdoc} * From 86a8a2d1599de399dd274b2b260fd26fa128050b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Auswo=CC=88ger?= Date: Sat, 13 Feb 2021 22:30:19 +0100 Subject: [PATCH 2/3] Fix YCBCR colorspace --- src/Imagick/Imagine.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Imagick/Imagine.php b/src/Imagick/Imagine.php index daad633ca..91ebc491a 100644 --- a/src/Imagick/Imagine.php +++ b/src/Imagick/Imagine.php @@ -193,6 +193,19 @@ private function createPalette(\Imagick $imagick) return new CMYK(); case \Imagick::COLORSPACE_GRAY: return new Grayscale(); + case \Imagick::COLORSPACE_YCBCR: + try { + $profile = $imagick->getImageProfile('icc'); + } catch (\ImagickException $e) { + $profile = null; + } + $imagick->transformImageColorspace(\Imagick::COLORSPACE_SRGB); + + if ($profile) { + $imagick->setImageProfile('icc', $profile); + } + + return new RGB(); default: throw new NotSupportedException('Only RGB and CMYK colorspace are currently supported'); } From fd4b70961a3067937d5537f395ad16f0c5fc965b Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Thu, 30 Sep 2021 11:18:47 +0200 Subject: [PATCH 3/3] Minor code optimization --- src/Imagick/Image.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Imagick/Image.php b/src/Imagick/Image.php index 277c963ec..25fa4fa26 100644 --- a/src/Imagick/Image.php +++ b/src/Imagick/Image.php @@ -832,19 +832,20 @@ private function applyImageOptions(\Imagick $image, array $options, $path) break; case 'avif': case 'heic': - if (!isset($options[$format . '_quality'])) { - if (isset($options['quality'])) { - $options[$format . '_quality'] = $options['quality']; - } - } - if (isset($options[$format . '_quality'])) { - $options[$format . '_quality'] = max(1, min(99, $options[$format . '_quality'])); - $image->setimagecompressionquality($options[$format . '_quality']); - $image->setcompressionquality($options[$format . '_quality']); - } if (!empty($options[$format . '_lossless'])) { $image->setimagecompressionquality(100); $image->setcompressionquality(100); + } else { + if (!isset($options[$format . '_quality'])) { + if (isset($options['quality'])) { + $options[$format . '_quality'] = $options['quality']; + } + } + if (isset($options[$format . '_quality'])) { + $options[$format . '_quality'] = max(1, min(99, $options[$format . '_quality'])); + $image->setimagecompressionquality($options[$format . '_quality']); + $image->setcompressionquality($options[$format . '_quality']); + } } break; }