Skip to content
Snippets Groups Projects
Unverified Commit 71c58d67 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3202016 by mondrake, andypost, acbramley, mstrelan, hestenet, benmorss,...

Issue #3202016 by mondrake, andypost, acbramley, mstrelan, hestenet, benmorss, smustgrave, catch, alexpott, xjm, Mixologic: Let GDToolkit support AVIF image format
parent 616d1046
No related branches found
No related tags found
2 merge requests!2964Issue #2865710 : Dependencies from only one instance of a widget are used in display modes,!10223132456: Fix issue where views instances are emptied before an ajax request is complete
Pipeline #435530 passed with warnings
Pipeline: drupal

#435541

    Pipeline: drupal

    #435536

      Pipeline: drupal

      #435532

        ...@@ -48,6 +48,7 @@ core/.phpstan-baseline.php text eol=lf whitespace=blank-at-eol,-blank-at-eof,-sp ...@@ -48,6 +48,7 @@ core/.phpstan-baseline.php text eol=lf whitespace=blank-at-eol,-blank-at-eof,-sp
        # Define binary file attributes. # Define binary file attributes.
        # - Do not treat them as text. # - Do not treat them as text.
        # - Include binary diff in patches instead of "binary files differ." # - Include binary diff in patches instead of "binary files differ."
        *.avif -text diff
        *.eot -text diff *.eot -text diff
        *.exe -text diff *.exe -text diff
        *.gif -text diff *.gif -text diff
        ......
        ...@@ -34,6 +34,7 @@ autoplace ...@@ -34,6 +34,7 @@ autoplace
        autoplay autoplay
        autoreply autoreply
        autosubmit autosubmit
        avif
        backlink backlink
        bakeware bakeware
        barchart barchart
        ...@@ -234,6 +235,7 @@ icann ...@@ -234,6 +235,7 @@ icann
        iconwrap iconwrap
        idekey idekey
        iframeupload iframeupload
        imageavif
        imagecache imagecache
        indexname indexname
        inglés inglés
        ......
        ...@@ -270,7 +270,11 @@ public function save($destination) { ...@@ -270,7 +270,11 @@ public function save($destination) {
        } }
        else { else {
        // Image types that support alpha need to be saved accordingly. // Image types that support alpha need to be saved accordingly.
        if (in_array($this->getType(), [IMAGETYPE_PNG, IMAGETYPE_WEBP], TRUE)) { if (in_array($this->getType(), [
        IMAGETYPE_PNG,
        IMAGETYPE_WEBP,
        IMAGETYPE_AVIF,
        ], TRUE)) {
        imagealphablending($this->getImage(), FALSE); imagealphablending($this->getImage(), FALSE);
        imagesavealpha($this->getImage(), TRUE); imagesavealpha($this->getImage(), TRUE);
        } }
        ...@@ -428,8 +432,12 @@ public function getRequirements() { ...@@ -428,8 +432,12 @@ public function getRequirements() {
        IMG_JPG => 'JPEG', IMG_JPG => 'JPEG',
        IMG_PNG => 'PNG', IMG_PNG => 'PNG',
        IMG_WEBP => 'WEBP', IMG_WEBP => 'WEBP',
        IMG_AVIF => 'AVIF',
        ]; ];
        $supported_formats = array_filter($check_formats, fn($type) => imagetypes() & $type, ARRAY_FILTER_USE_KEY); $supported_formats = array_filter($check_formats, fn($type) => imagetypes() & $type, ARRAY_FILTER_USE_KEY);
        if (isset($supported_formats[IMG_AVIF]) && !$this->checkAvifSupport()) {
        unset($supported_formats[IMG_AVIF]);
        }
        $unsupported_formats = array_diff_key($check_formats, $supported_formats); $unsupported_formats = array_diff_key($check_formats, $supported_formats);
        $descriptions = []; $descriptions = [];
        ...@@ -454,6 +462,11 @@ public function getRequirements() { ...@@ -454,6 +462,11 @@ public function getRequirements() {
        '@unsupported' => $unsupported, '@unsupported' => $unsupported,
        '@ref' => $fix_info, '@ref' => $fix_info,
        ]); ]);
        if (isset($unsupported_formats[IMG_AVIF])) {
        $descriptions[] = $this->t('AVIF is not supported, likely because of PHP missing a codec for encoding images. See <a href=":cr_url">the change record</a> for more information.', [
        ':cr_url' => 'https://www.drupal.org/node/3348348',
        ]);
        }
        } }
        // Check for filter and rotate support. // Check for filter and rotate support.
        ...@@ -528,6 +541,31 @@ public function extensionToImageType($extension) { ...@@ -528,6 +541,31 @@ public function extensionToImageType($extension) {
        return IMAGETYPE_UNKNOWN; return IMAGETYPE_UNKNOWN;
        } }
        /**
        * Checks if AVIF can encode image.
        *
        * This method tries to create an AVIF image and save it to disk via
        * imageavif(). If that fails, it's likely a codec missing, or the function
        * was disabled. This is an expensive operation to run, so we cache its
        * result.
        *
        * @return bool
        * TRUE if AVIF is fully supported, FALSE otherwise.
        */
        protected function checkAvifSupport(): bool {
        static $supported = NULL;
        if ($supported !== NULL) {
        return $supported;
        }
        $tempFile = fopen('php://memory', 'r+');
        $supported = imageavif(imagecreatetruecolor(1, 1), $tempFile, 0, 10) && fstat($tempFile)['size'] > 0;
        fclose($tempFile);
        return $supported;
        }
        /** /**
        * Returns a list of image types supported by the toolkit. * Returns a list of image types supported by the toolkit.
        * *
        ...@@ -536,7 +574,13 @@ public function extensionToImageType($extension) { ...@@ -536,7 +574,13 @@ public function extensionToImageType($extension) {
        * IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG, IMAGETYPE_PNG, etc.). * IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG, IMAGETYPE_PNG, etc.).
        */ */
        protected static function supportedTypes() { protected static function supportedTypes() {
        return [IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_WEBP]; return [
        IMAGETYPE_PNG,
        IMAGETYPE_JPEG,
        IMAGETYPE_GIF,
        IMAGETYPE_WEBP,
        IMAGETYPE_AVIF,
        ];
        } }
        } }
        ...@@ -92,6 +92,7 @@ protected function execute(array $arguments) { ...@@ -92,6 +92,7 @@ protected function execute(array $arguments) {
        switch ($type) { switch ($type) {
        case IMAGETYPE_PNG: case IMAGETYPE_PNG:
        case IMAGETYPE_WEBP: case IMAGETYPE_WEBP:
        case IMAGETYPE_AVIF:
        imagealphablending($image, FALSE); imagealphablending($image, FALSE);
        $transparency = imagecolorallocatealpha($image, 0, 0, 0, 127); $transparency = imagecolorallocatealpha($image, 0, 0, 0, 127);
        imagefill($image, 0, 0, $transparency); imagefill($image, 0, 0, $transparency);
        ......
        ...@@ -83,7 +83,7 @@ public function testGdToolkitRequirements(): void { ...@@ -83,7 +83,7 @@ public function testGdToolkitRequirements(): void {
        // Get Status Report. // Get Status Report.
        $this->drupalGet('admin/reports/status'); $this->drupalGet('admin/reports/status');
        $this->assertSession()->pageTextContains('GD2 image manipulation toolkit'); $this->assertSession()->pageTextContains('GD2 image manipulation toolkit');
        $this->assertSession()->pageTextContains('Supported image file formats: GIF, JPEG, PNG, WEBP.'); $this->assertSession()->pageTextContains('Supported image file formats: GIF, JPEG, PNG, WEBP, AVIF.');
        } }
        } }
        ...@@ -192,6 +192,13 @@ public static function providerTestImageFiles(): array { ...@@ -192,6 +192,13 @@ public static function providerTestImageFiles(): array {
        'arguments' => ['extension' => 'webp'], 'arguments' => ['extension' => 'webp'],
        'corners' => $default_corners, 'corners' => $default_corners,
        ], ],
        'convert_avif' => [
        'operation' => 'convert',
        'width' => 40,
        'height' => 20,
        'arguments' => ['extension' => 'avif'],
        'corners' => $default_corners,
        ],
        ]; ];
        // Systems using non-bundled GD2 may miss imagerotate(). Test if available. // Systems using non-bundled GD2 may miss imagerotate(). Test if available.
        ...@@ -262,6 +269,7 @@ public static function providerTestImageFiles(): array { ...@@ -262,6 +269,7 @@ public static function providerTestImageFiles(): array {
        'image-test-no-transparency.gif', 'image-test-no-transparency.gif',
        'image-test.jpg', 'image-test.jpg',
        'img-test.webp', 'img-test.webp',
        'img-test.avif',
        ] as $file_name) { ] as $file_name) {
        foreach ($test_cases as $test_case => $values) { foreach ($test_cases as $test_case => $values) {
        $operation = $values['operation']; $operation = $values['operation'];
        ...@@ -340,8 +348,11 @@ public function testManipulations(string $file_name, string $test_case, string $ ...@@ -340,8 +348,11 @@ public function testManipulations(string $file_name, string $test_case, string $
        continue; continue;
        } }
        // JPEG has small differences in color after processing. // JPEG and AVIF have small differences in color after processing.
        $tolerance = $image_original_type === IMAGETYPE_JPEG ? 3 : 0; $tolerance = match($image_original_type) {
        IMAGETYPE_JPEG, IMAGETYPE_AVIF => 3,
        default => 0,
        };
        $this->assertColorsAreEqual($expected_color, $actual_color, $tolerance, "Image '$file_name' object after '$test_case' action has the correct color placement at corner '$key'"); $this->assertColorsAreEqual($expected_color, $actual_color, $tolerance, "Image '$file_name' object after '$test_case' action has the correct color placement at corner '$key'");
        } }
        ...@@ -357,7 +368,7 @@ public function testManipulations(string $file_name, string $test_case, string $ ...@@ -357,7 +368,7 @@ public function testManipulations(string $file_name, string $test_case, string $
        */ */
        public function testSupportedExtensions(): void { public function testSupportedExtensions(): void {
        // Test the list of supported extensions. // Test the list of supported extensions.
        $expected_extensions = ['png', 'gif', 'jpeg', 'jpg', 'jpe', 'webp']; $expected_extensions = ['png', 'gif', 'jpeg', 'jpg', 'jpe', 'webp', 'avif'];
        $this->assertEqualsCanonicalizing($expected_extensions, $this->imageFactory->getSupportedExtensions()); $this->assertEqualsCanonicalizing($expected_extensions, $this->imageFactory->getSupportedExtensions());
        // Test that the supported extensions map to correct internal GD image // Test that the supported extensions map to correct internal GD image
        ...@@ -369,6 +380,7 @@ public function testSupportedExtensions(): void { ...@@ -369,6 +380,7 @@ public function testSupportedExtensions(): void {
        'jpg' => IMAGETYPE_JPEG, 'jpg' => IMAGETYPE_JPEG,
        'jpe' => IMAGETYPE_JPEG, 'jpe' => IMAGETYPE_JPEG,
        'webp' => IMAGETYPE_WEBP, 'webp' => IMAGETYPE_WEBP,
        'avif' => IMAGETYPE_AVIF,
        ]; ];
        $image = $this->imageFactory->get(); $image = $this->imageFactory->get();
        foreach ($expected_image_types as $extension => $expected_image_type) { foreach ($expected_image_types as $extension => $expected_image_type) {
        ...@@ -385,6 +397,7 @@ public static function providerSupportedImageTypes(): array { ...@@ -385,6 +397,7 @@ public static function providerSupportedImageTypes(): array {
        [IMAGETYPE_GIF], [IMAGETYPE_GIF],
        [IMAGETYPE_JPEG], [IMAGETYPE_JPEG],
        [IMAGETYPE_WEBP], [IMAGETYPE_WEBP],
        [IMAGETYPE_AVIF],
        ]; ];
        } }
        ...@@ -517,7 +530,7 @@ public function testGetRequirements(): void { ...@@ -517,7 +530,7 @@ public function testGetRequirements(): void {
        'version' => [ 'version' => [
        'title' => 'GD library', 'title' => 'GD library',
        'value' => gd_info()['GD Version'], 'value' => gd_info()['GD Version'],
        'description' => sprintf("Supported image file formats: %s.", implode(', ', ['GIF', 'JPEG', 'PNG', 'WEBP'])), 'description' => sprintf("Supported image file formats: %s.", implode(', ', ['GIF', 'JPEG', 'PNG', 'WEBP', 'AVIF'])),
        ], ],
        ], $this->imageFactory->get()->getToolkit()->getRequirements()); ], $this->imageFactory->get()->getToolkit()->getRequirements());
        } }
        ......
        File added
        0% Loading or .
        You are about to add 0 people to the discussion. Proceed with caution.
        Finish editing this message first!
        Please register or to comment