Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert PNG to AVIF/WebP on upload #371

Closed
mxbclang opened this issue Jun 13, 2022 · 48 comments · Fixed by #1421
Closed

Convert PNG to AVIF/WebP on upload #371

mxbclang opened this issue Jun 13, 2022 · 48 comments · Fixed by #1421
Assignees
Labels
[Plugin] Modern Image Formats Issues for the Modern Image Formats plugin (formerly WebP Uploads) [Plugin] Performance Lab Issue relates to work in the Performance Lab Plugin only [Type] Enhancement A suggestion for improvement of an existing feature

Comments

@mxbclang
Copy link
Contributor

As noted in this support topic, add the ability to automatically convert PNG images to WebP.

@mxbclang mxbclang added [Type] Enhancement A suggestion for improvement of an existing feature [Focus] Images [Plugin] Modern Image Formats Issues for the Modern Image Formats plugin (formerly WebP Uploads) labels Jun 13, 2022
@felixarntz felixarntz added the Needs Discussion Anything that needs a discussion/agreement label Jun 16, 2022
@erikyo
Copy link

erikyo commented Jun 24, 2022

I think it's definitely a good idea 💯
if jpgs are not always the ideal source for webp encoding, because the result vary depending on the source quality, pngs would give amazing results -- especially considering that a lossy webp weighs up to 20 times less than a png (png -> webp lossy). This would be a nice performance boost!
Another advantage is that in this case there we have generation loss so, at the same SSIM, the images will weight about the 30% compared to a standard jpg.

there would be two options:

  • convert the png to lossy
  • convert the png to lossless

My vote goes for png->lossy because the images of websites aren't intended to be 1:1 with the original so we can take the advantage of the compression techniques like chroma subsampling that decimates the image filesize.

Another suggestion is to use the png as the source image and not to create the subsizes in png.
I currently use exactly this way: I upload png images that I keep it only as source in order to create the copy and subsizes in webp. In this way I get much higher quality than a jpg, it takes up less space, and I only have one extra image (the source png).

EDIT: the bug of the webp missing transparency is related to versions before gd 2.1.1 (6 years ago, php 5.6)... I forgot to mention about, but i guess actually isn't a real issue since it's deprecated. here more info

@felixarntz felixarntz added the [Plugin] Performance Lab Issue relates to work in the Performance Lab Plugin only label Jul 19, 2023
@maisondasilva
Copy link

@felixarntz Any news about this, I loved the plugin, but most of my images are .png and that would be very good, I did an online conversion test and saw that the images would be half the size!

Thanks

@nikolasholm
Copy link

Any update on this yet?

@ficod
Copy link

ficod commented Apr 10, 2024

Any plans on this feature? First post in this thread is dated Jun 13, 2022...
Is there any progress made or it's just "planned for the future"?

@predaytor
Copy link

@ficod, yeah, I decided to convert them manually with Imagick:

<?php

namespace App\Media;

/**
 * Set image quality based on mime type.
 *
 * @param int    $quality    The image quality level.
 * @param string $mime_type  The mime type of the image.
 *
 * @return int The modified image quality level.
 */
function set_image_quality($quality, $mime_type)
{
    // Check if the mime type is 'image/webp'
    if ('image/webp' === $mime_type) {
        // Set a higher quality level for 'image/webp'
        return 86;
    }

    // Return the original quality level for other mime types
    return $quality;
}

// Add a filter to set image quality
add_filter('wp_editor_set_quality', __NAMESPACE__ . '\\set_image_quality', 10, 2);

///

/**
 * Scale down and optimize uploading image.
 *
 * @param array $file The uploading file information.
 * @return array The modified file information.
 */
function resize_preupload_image($file)
{
	$allowed_types = array('image/png', 'image/bmp', 'image/jpeg', 'image/jpg', 'image/webp');

	// Check mime type
	// Check if Imagick extension is available
	if (!in_array($file['type'], $allowed_types) || !class_exists('Imagick', false) || !class_exists('ImagickPixel', false)) {
		return $file;
	}

	// Check size limit
	$limit = 24000;
	$size = $file['size'] / 1024;

	if ($size > $limit) {
		$file['error'] = "Image files must be smaller than {$limit}kb";
		return $file;
	}

	// Get the temporary image path
	$filepath = $file['tmp_name'];

	// Get the file's dimensions
	list($image_width, $image_height) = @getimagesize($filepath);

	// Calculate the new dimensions for scaling
	$max_width = <YOUR_MAX_WIDTH_NUMBER>;
	$max_height = intval($image_height * ($max_width / $image_width));

	// Create a new Imagick object from the uploaded image
	$image = new \Imagick($filepath);

	// Get original image size
	$original_size = strlen($image->getImageBlob());

	// Check if image already has webp format (do not change quality)
	if ('image/webp' === $file['type']) {
		$image->setImageCompressionQuality(100);
	} else {
		// Set webp format (support transparency)
		$image->setImageFormat('webp');
		// Set image compression quality
		$image->setImageCompressionQuality(86);
	}

	// Scale down the image to the new dimensions
	$image->resizeImage(min($image_width, $max_width), min($image_height, $max_height), \Imagick::FILTER_CATROM, 1);

	// Get resized (webp converted) image size
	$resized_size = strlen($image->getImageBlob());

	// Check if the resized image has a larger file size than the original
	if ($resized_size >= $original_size) {
		// Original image has smaller or equal size, so keep it
		$image->clear();
		return $file;
	}

	// Save the resized image, overwrite the original file
	$image->writeImage($filepath);
	$file['size'] = $resized_size;
	$image->clear();

	// Return result
	return $file;
}
add_action('wp_handle_upload_prefilter', __NAMESPACE__ . '\\resize_preupload_image', 10, 1);

@adamsilverstein
Copy link
Member

adamsilverstein commented Apr 11, 2024

Now that we have landed AVIF support in core, the current "WebP Uploads" image plugin could be expanded to include support for AVIF. This would also be good opportunity to add some more flexibility around input formats we handle, or progressive encoding (also new in 6.5).

@ficod, yeah, I decided to convert them manually with Imagick:

@predaytor - Here is are some alternate approaches:

To filter the mime types that the WebP Uploads plugin transforms, use the webp_uploads_upload_image_mime_transforms filter:

add_filter( 'webp_uploads_upload_image_mime_transforms', function( $transforms ) {
	$transforms['image/png'] = array( 'image/png', 'image/webp' );
	return $transforms;
} );

To leverage the core filter directly:

add_filter( 'image_editor_output_format', function( $mappings ) {
	$mappings['image/png'] = 'image/webp';
	return $mappings;
} );

@ficod
Copy link

ficod commented Apr 12, 2024

@adamsilverstein @predaytor Thank you all for your replies.

What I don't understand is why this plugin can't receive an official update to solve the issue.
This issue is totally not taken care of, is it considered not important or the project is not being actively developed?

I ended up preferring another plugin: WebP Express

@benoitfouc
Copy link

benoitfouc commented Apr 15, 2024

AVIF do not support transparency like the PNG format.

AVIF is a good alternative for JPEG files
And WebP is the best alternative for PNG files because WebP support transparency.

So, this plugin being to be useless since the AVIF is now supported by the core and since this plugin do not support convert PNG files to WebP.

We just need a new plugin to convert automaticly WEBP, JPEG and PNG files into AVIF

@erikyo
Copy link

erikyo commented Apr 15, 2024

Sorry but this is wrong! avif image format fully support alpha channel (the transparency)
https://avif.io/blog/faq/avif-transparency/

Addy Osmani has written a nice book on the argument, recommended
https://www.smashingmagazine.com/2021/09/modern-image-formats-avif-webp/

@benoitfouc
Copy link

benoitfouc commented Apr 24, 2024

Now that the Modern Images Formats plugin will support AVIF format (output), thanks to @adamsilverstein on #1151.
I think the next logical evolution is to support more input like the PNG format.

Adam make this one, for his plugin, what do you think about that setting page ?

image

Leave the choice for users to convert a JPEG input into AVIF, PNG input into WebP, and WebP input into AVIF (for example) that can be a great evolution for our Modern Images Formats plugin and it will be more consistent with the new plugin name 😉

@westonruter
Copy link
Member

westonruter commented Jun 10, 2024

@phanduynam
Copy link

Please update the topic to add PNG to Avif image format conversion

@westonruter westonruter changed the title Convert PNG to WebP on upload Convert PNG to AVIF/WebP on upload Jun 24, 2024
@bolach
Copy link

bolach commented Jun 30, 2024

This is the only reason why i don't use this plugin. No .png support :(

@adamsilverstein
Copy link
Member

adamsilverstein commented Jul 2, 2024

Let's try to land wider support for uploaded images, including PNGs.

The biggest question I have is about the best UI to provide.

For my plugin (pictured above) I went with giving users full control of the output format they want for each input format, but that me a bit over the top for this plugin? Maybe we can use a simplified approach where you choose an output format, then you choose from a checkbox list of input formats, choosing the ones you want to transform? Or maybe just automatically transform any uploaded images when we can reasonably do so?

@westonruter
Copy link
Member

@adamsilverstein Yeah, I do think that would be over-the-top to provide such granularity. With considering decisions not options, should JPEG and PNG always be converted to AVIF? Or would there be scenarios where one should rather be converted to WebP? Like, as I understand, only lossless AVIF supports transparency. So would perhaps all JPEGs be converted to AVIF as well as all non-transparent PNGs, but then leave transparent PNGs to converted to WebP (lossless or lossy)?

For sites that want to have fine-tuned control, I'd think that we'd perhaps offer a filter instead of a UI for that.

@adamsilverstein
Copy link
Member

For sites that want to have fine-tuned control, I'd think that we'd perhaps offer a filter instead of a UI for that.

that makes sense, possibly a filter against whatever we decide are the defaults. existing core filters the plugin itself uses could already be used to fine tune the final behavior.

only lossless AVIF supports transparency. So would perhaps all JPEGs be converted to AVIF as well as all non-transparent PNGs, but then leave transparent PNGs to converted to WebP (lossless or lossy)?

interesting point, for transparent images, WebP lossy is probably the best choice. I like the general direction of mapping to what we think is the best available output type for the input type. I will work on a PR with that approach and we can discuss further.

@erikyo
Copy link

erikyo commented Jul 3, 2024

Like, as I understand, only lossless AVIF supports transparency

Afaik (but I can be wrong) lossy avifs also support the alpha channel (the transparency). you can give a try with squoosh and converting a transparent image to avif (for me has worked)

As to which is "preferred" I prepared this which converts random images and measures their PSNR / SSIM ( spoiler: in the end avif always wins)
https://gist.github.com/erikyo/d6ef961adc95a5c74e376a0216b29f69

the only doubts about whether to use avif or not is the time it takes to convert images which is hundreds of times longer than converting a jpeg, this in some cases (e.g. image regeneration by woocommerce) leads to unexpected results

@phanduynam
Copy link

phanduynam commented Jul 3, 2024

I was wondering if you could address this request when it launches with WordPress 6.6? This request has been raised and pending for 2 years and still has not been resolved.

@westonruter
Copy link
Member

@erikyo

Afaik (but I can be wrong) lossy avifs also support the alpha channel (the transparency). you can give a try with squoosh and converting a transparent image to avif (for me has worked)

Interesting. I was just going off of what I found in search. For example via shortpixel.com:

AVIF supports transparency for lossless images but doesn’t support transparency for lossy images. On the other hand, WebP is the only image format that supports RGB channel transparency for lossy images.

I guess that's just wrong.

the only doubts about whether to use avif or not is the time it takes to convert images which is hundreds of times longer than converting a jpeg, this in some cases (e.g. image regeneration by woocommerce) leads to unexpected results

That's a great point. I've seen approaches where the WebP is generated first since it is fast, with the AVIF generation then sent to a background process since it can take a long time.

@adamsilverstein
Copy link
Member

@erikyo, with ImageMagick you can try setting 'heic:speed' to 6 or 7 for AVIF. libheif looks like it defaults libaom to speed 0, the slowest setting.

Imagick says it uses 5 as the default value - although I didn't see that default in the code.

I created a simple PR to change the default for WordPress Imagick AVIF handling to 7 - WordPress/wordpress-develop#7068

@adamsilverstein
Copy link
Member

@adamsilverstein, it would be great if you could test AVIF vs. WebP encoding and decoding with WordPress. As you’ve seen, my tests use ImageMagick (like WordPress), but it’s always better to have real-world tests!

@erikyo -

I created this mini plugin to test processing time by mime type using WordPress - https://gist.github.com/adamsilverstein/b4e91c9ab1e6f546ec98e3dcc53afb7d

Times were too fast in my local to me meaningful to measure. I need to test it in a slower environment to measure actual performance, or modify to run the process repeatedly.

@erikyo
Copy link

erikyo commented Jul 22, 2024

@jzern Below the tests using different speeds and quality settings for the AVIF format. It seems you are right about that, the "heic:speed" option greatly reduces time without interfering with quality too much.

avif / testing quality + heic:speed (updated with some line charts at the end of the file)

@adamsilverstein thanks again, here are the results:

2k image jpg 2000x2400
{
     "profiling_data": [
         {
             "format": "image\/jpeg",
             "size": {
                 "width": 300,
                 "height": 300
             },
             "filesize": 78452,
             "time": 0.027272939682006836
         },
         {
             "format": "image\/jpeg",
             "size": {
                 "width": 600,
                 "height": 600
             },
             "filesize": 78452,
             "time": 0.0017361640930175781
         },
         {
             "format": "image\/jpeg",
             "size": {
                 "width": 1200,
                 "height": 1200
             },
             "filesize": 78452,
             "time": 0.0017290115356445312
         },
         {
             "format": "image\/jpeg",
             "size": {
                 "width": 2400,
                 "height": 2400
             },
             "filesize": 78452,
             "time": 0.001683950424194336
         },
         {
             "format": "image\/webp",
             "size": {
                 "width": 300,
                 "height": 300
             },
             "filesize": 79732,
             "time": 0.03746390342712402
         },
         {
             "format": "image\/webp",
             "size": {
                 "width": 600,
                 "height": 600
             },
             "filesize": 79732,
             "time": 0.012015819549560547
         },
         {
             "format": "image\/webp",
             "size": {
                 "width": 1200,
                 "height": 1200
             },
             "filesize": 79732,
             "time": 0.01200103759765625
         },
         {
             "format": "image\/webp",
             "size": {
                 "width": 2400,
                 "height": 2400
             },
             "filesize": 79732,
             "time": 0.011939048767089844
         },
         {
             "format": "image\/avif",
             "size": {
                 "width": 300,
                 "height": 300
             },
             "filesize": 12328,
             "time": 0.21320605278015137
         },
         {
             "format": "image\/avif",
             "size": {
                 "width": 600,
                 "height": 600
             },
             "filesize": 12328,
             "time": 0.1872880458831787
         },
         {
             "format": "image\/avif",
             "size": {
                 "width": 1200,
                 "height": 1200
             },
             "filesize": 12328,
             "time": 0.18783307075500488
         },
         {
             "format": "image\/avif",
             "size": {
                 "width": 2400,
                 "height": 2400
             },
             "filesize": 12328,
             "time": 0.19110894203186035
         }
     ],
     "total_time": {
         "image\/jpeg": {
             "start": 1721671552.943534,
             "end": 1721671552.975962,
             "total": 0.03242802619934082
         },
         "image\/webp": {
             "start": 1721671553.005592,
             "end": 1721671553.079016,
             "total": 0.07342386245727539
         },
         "image\/avif": {
             "start": 1721671553.108473,
             "end": 1721671553.887918,
             "total": 0.7794449329376221
         }
     }
 }
```
--------------------------------------
format, size, time
image/jpeg, 300x300, 0.027272939682007
image/jpeg, 600x600, 0.0017361640930176
image/jpeg, 1200x1200, 0.0017290115356445
image/jpeg, 2400x2400, 0.0016839504241943
image/webp, 300x300, 0.037463903427124
image/webp, 600x600, 0.012015819549561
image/webp, 1200x1200, 0.012001037597656
image/webp, 2400x2400, 0.01193904876709
image/avif, 300x300, 0.21320605278015
image/avif, 600x600, 0.18728804588318
image/avif, 1200x1200, 0.187833070755
image/avif, 2400x2400, 0.19110894203186
```
png image 3600x2700
 {
     "profiling_data": [
         {
             "format": "image\/jpeg",
             "size": {
                 "width": 300,
                 "height": 300
             },
             "filesize": 15270,
             "time": 0.030642032623291016
         },
         {
             "format": "image\/jpeg",
             "size": {
                 "width": 600,
                 "height": 600
             },
             "filesize": 15270,
             "time": 0.0013499259948730469
         },
         {
             "format": "image\/jpeg",
             "size": {
                 "width": 1200,
                 "height": 1200
             },
             "filesize": 15270,
             "time": 0.0013699531555175781
         },
         {
             "format": "image\/jpeg",
             "size": {
                 "width": 2400,
                 "height": 2400
             },
             "filesize": 15270,
             "time": 0.0014090538024902344
         },
         {
             "format": "image\/webp",
             "size": {
                 "width": 300,
                 "height": 300
             },
             "filesize": 13284,
             "time": 0.033232927322387695
         },
         {
             "format": "image\/webp",
             "size": {
                 "width": 600,
                 "height": 600
             },
             "filesize": 13284,
             "time": 0.010429859161376953
         },
         {
             "format": "image\/webp",
             "size": {
                 "width": 1200,
                 "height": 1200
             },
             "filesize": 13284,
             "time": 0.010452032089233398
         },
         {
             "format": "image\/webp",
             "size": {
                 "width": 2400,
                 "height": 2400
             },
             "filesize": 13284,
             "time": 0.010426044464111328
         },
         {
             "format": "image\/avif",
             "size": {
                 "width": 300,
                 "height": 300
             },
             "filesize": 5811,
             "time": 0.16109609603881836
         },
         {
             "format": "image\/avif",
             "size": {
                 "width": 600,
                 "height": 600
             },
             "filesize": 5811,
             "time": 0.1379549503326416
         },
         {
             "format": "image\/avif",
             "size": {
                 "width": 1200,
                 "height": 1200
             },
             "filesize": 5811,
             "time": 0.13739490509033203
         },
         {
             "format": "image\/avif",
             "size": {
                 "width": 2400,
                 "height": 2400
             },
             "filesize": 5811,
             "time": 0.13708209991455078
         }
     ],
     "total_time": {
         "image\/jpeg": {
             "start": 1721672632.182837,
             "end": 1721672632.217613,
             "total": 0.03477597236633301
         },
         "image\/webp": {
             "start": 1721672632.550024,
             "end": 1721672632.614569,
             "total": 0.0645449161529541
         },
         "image\/avif": {
             "start": 1721672632.946851,
             "end": 1721672633.520387,
             "total": 0.5735359191894531
         }
     }
 }
```
--------------------------------------
format, size, time
image/jpeg, 300x300, 0.027272939682007
image/jpeg, 600x600, 0.0017361640930176
image/jpeg, 1200x1200, 0.0017290115356445
image/jpeg, 2400x2400, 0.0016839504241943
image/webp, 300x300, 0.037463903427124
image/webp, 600x600, 0.012015819549561
image/webp, 1200x1200, 0.012001037597656
image/webp, 2400x2400, 0.01193904876709
image/avif, 300x300, 0.21320605278015
image/avif, 600x600, 0.18728804588318
image/avif, 1200x1200, 0.187833070755
image/avif, 2400x2400, 0.19110894203186
```
very large png image 4300x2850
 {
   "profiling_data": [
     {
       "format": "image\/jpeg",
       "size": {
         "width": 300,
         "height": 300
       },
       "filesize": 10764,
       "time": 0.023726940155029297
     },
     {
       "format": "image\/jpeg",
       "size": {
         "width": 600,
         "height": 600
       },
       "filesize": 10764,
       "time": 0.001238107681274414
     },
     {
       "format": "image\/jpeg",
       "size": {
         "width": 1200,
         "height": 1200
       },
       "filesize": 10764,
       "time": 0.0012209415435791016
     },
     {
       "format": "image\/jpeg",
       "size": {
         "width": 2400,
         "height": 2400
       },
       "filesize": 10764,
       "time": 0.0011870861053466797
     },
     {
       "format": "image\/webp",
       "size": {
         "width": 300,
         "height": 300
       },
       "filesize": 8844,
       "time": 0.03127789497375488
     },
     {
       "format": "image\/webp",
       "size": {
         "width": 600,
         "height": 600
       },
       "filesize": 8844,
       "time": 0.008497953414916992
     },
     {
       "format": "image\/webp",
       "size": {
         "width": 1200,
         "height": 1200
       },
       "filesize": 8844,
       "time": 0.008488893508911133
     },
     {
       "format": "image\/webp",
       "size": {
         "width": 2400,
         "height": 2400
       },
       "filesize": 8844,
       "time": 0.008411169052124023
     },
     {
       "format": "image\/avif",
       "size": {
         "width": 300,
         "height": 300
       },
       "filesize": 3431,
       "time": 0.1293962001800537
     },
     {
       "format": "image\/avif",
       "size": {
         "width": 600,
         "height": 600
       },
       "filesize": 3431,
       "time": 0.1075899600982666
     },
     {
       "format": "image\/avif",
       "size": {
         "width": 1200,
         "height": 1200
       },
       "filesize": 3431,
       "time": 0.10776495933532715
     },
     {
       "format": "image\/avif",
       "size": {
         "width": 2400,
         "height": 2400
       },
       "filesize": 3431,
       "time": 0.10826396942138672
     }
   ],
   "total_time": {
     "image\/jpeg": {
       "start": 1721673332.803404,
       "end": 1721673332.830782,
       "total": 0.027377843856811523
     },
     "image\/webp": {
       "start": 1721673333.215625,
       "end": 1721673333.272304,
       "total": 0.05667901039123535
     },
     "image\/avif": {
       "start": 1721673333.657167,
       "end": 1721673334.11019,
       "total": 0.45302295684814453
     }
   }
 }
```
image/jpeg, 300x300, 0.023726940155029
image/jpeg, 600x600, 0.0012381076812744
image/jpeg, 1200x1200, 0.0012209415435791
image/jpeg, 2400x2400, 0.0011870861053467
image/webp, 300x300, 0.031277894973755
image/webp, 600x600, 0.008497953414917
image/webp, 1200x1200, 0.0084888935089111
image/webp, 2400x2400, 0.008411169052124
image/avif, 300x300, 0.12939620018005
image/avif, 600x600, 0.10758996009827
image/avif, 1200x1200, 0.10776495933533
image/avif, 2400x2400, 0.10826396942139

image

a small consideration about this. the 300x300 images takes more time to be processed, probably due to the time required time to resize the image with the sinc-lanczos filter. this pattern is repeated for all of these formats as well

My server specs:
Server architecture | Linux 5.15.0-116-generic x86_64
cpu Intel(R) Core(TM) i5-7500T CPU @ 2.70GHz, 4 cores
memory 7.63 GiB total	
Web server | nginx/1.18.0
PHP version | 7.4.33 (Supports 64bit values)
PHP SAPI | fpm-fcgi
PHP max input variables | 1000
PHP time limit | 120
PHP memory limit | 512M
Max input time | 120
Upload max filesize | 128M
PHP post max size | 128M
cURL version | 7.81.0 OpenSSL/3.0.2
Is SUHOSIN installed? | No
Is the Imagick library available? | Yes
Are pretty permalinks supported? | Yes
Current time | 2024-07-22T18:43:30+00:00
Current UTC time | Monday, 22-Jul-24 18:43:30 UTC
Current Server time | 2024-07-22T19:43:28+01:00


ImageMagick version number | 1691
ImageMagick version string | ImageMagick 6.9.11-60 Q16 x86_64 2021-01-25 https://imagemagick.org
Imagick version | 3.7.0
File uploads | Enabled
Maximum size of post data allowed | 128M
Maximum size of an uploaded file | 128M
Maximum effective file size | 128 MB
Maximum number of files allowed | 20
Imagick Resource Limits | area: 122 MBdisk: 1073741824file: 768map: 512 MBmemory: 256 MBthread: 1time: 9.2233720368548E+18
ImageMagick-supported file formats | 3FR, 3G2, 3GP, AAI, AI, APNG, ART, ARW, AVI, AVIF, AVS, BGR, BGRA, BGRO, BIE, BMP, BMP2, BMP3, BRF, CAL, CALS, CANVAS, CAPTION, CIN, CIP, CLIP, CMYK, CMYKA, CR2, CR3, CRW, CUR, CUT, DATA, DCM, DCR, DCX, DDS, DFONT, DNG, DPX, DXT1, DXT5, EPDF, EPI, EPS, EPS2, EPS3, EPSF, EPSI, EPT, EPT2, EPT3, ERF, FAX, FILE, FITS, FRACTAL, FTP, FTS, G3, G4, GIF, GIF87, GRADIENT, GRAY, GRAYA, GROUP4, H, HALD, HDR, HEIC, HISTOGRAM, HRZ, HTM, HTML, HTTP, HTTPS, ICB, ICO, ICON, IIQ, INFO, INLINE, IPL, ISOBRL, ISOBRL6, J2C, J2K, JBG, JBIG, JNG, JNX, JP2, JPC, JPE, JPEG, JPG, JPM, JPS, JPT, JSON, K25, KDC, LABEL, M2V, M4V, MAC, MAGICK, MAP, MASK, MAT, MATTE, MEF, MIFF, MKV, MNG, MONO, MOV, MP4, MPC, MPG, MRW, MSL, MTV, MVG, NEF, NRW, NULL, ORF, OTB, OTF, PAL, PALM, PAM, PATTERN, PBM, PCD, PCDS, PCL, PCT, PCX, PDB, PDF, PDFA, PEF, PES, PFA, PFB, PFM, PGM, PGX, PICON, PICT, PIX, PJPEG, PLASMA, PNG, PNG00, PNG24, PNG32, PNG48, PNG64, PNG8, PNM, POCKETMOD, PPM, PREVIEW, PS, PS2, PS3, PSB, PSD, PTIF, PWP, RADIAL-GRADIENT, RAF, RAS, RAW, RGB, RGBA, RGBO, RGF, RLA, RLE, RMF, RW2, SCR, SCT, SFW, SGI, SHTML, SIX, SIXEL, SPARSE-COLOR, SR2, SRF, STEGANO, SUN, TEXT, TGA, THUMBNAIL, TIFF, TIFF64, TILE, TIM, TTC, TTF, TXT, UBRL, UBRL6, UIL, UYVY, VDA, VICAR, VID, VIDEO, VIFF, VIPS, VST, WBMP, WEBM, WEBP, WMV, WPG, X, X3F, XBM, XC, XCF, XPM, XPS, XV, XWD, YCbCr, YCbCrA, YUV
GD version | 2.3.3
GD supported file formats | GIF, JPEG, PNG, WebP, BMP, XPM
Ghostscript version | 9.55.0

@y-guyon Thanks so much for providing such interesting information! will try asap also with the avif codec. I have chosen the heic one since that Colab script is from 2 years ago, and at that time the heic codec was much more widespread and (if I remember correctly) was also faster

I would, however, like to point out that the command from the command line is used and instead WordPress uses Imagick, which is not performing in the same way. The biggest limitation in this case would be the number of cores used to convert the image than with imagemagick it should only use 1 core for each file converted

@adamsilverstein
Copy link
Member

@erikyo thanks for sharing those results. Clearly the AVIF generation is taking much longer than the other formats - still the slowest time was well under a second, so for average use in WordPress this might be OK. I'll try to repeat the experiment on a lower end server as well as expanding the code to run a large number of repetitions.

@jzern Bellow the tests using different speeds and quality settings for the AVIF format. It seems you are right about that, the "heic:speed" option greatly reduces time without interfering with quality too much.

Seems likely we should change the default for WordPress (from 5) to 7

@jzern
Copy link

jzern commented Jul 23, 2024

@jzern Bellow the tests using different speeds and quality settings for the AVIF format. It seems you are right about that, the "heic:speed" option greatly reduces time without interfering with quality too much.

Thanks for testing it out. The results look reasonable.

Seems likely we should change the default for WordPress (from 5) to 7

libavif's default is 6; either that or 7 should be a good default.

@erikyo
Copy link

erikyo commented Jul 23, 2024

To verify, I modified the script so that it now uses only the full-size image and tests the quality vs ‘heif:speed’ vs time

test 2

It is even clearer that there is no quality loss with speed = 7. However, since the default speed for ImageMagick is 6, changing it to 7 is unlikely to affect the encoding performance significantly.

@adamsilverstein
Copy link
Member

It is even clearer that there is no quality loss with speed = 7. However, since the default speed for ImageMagick is 6, changing it to 7 is unlikely to affect the encoding performance significantly.

Somewhere I saw a default of 5 mentioned for Imagick (although I didn't find the code), perhaps it is readable so I will try to check it. Still if quality isn't adversely affected, probably worth raising given the very slow encoding speed.

@jzern
Copy link

jzern commented Jul 24, 2024

Somewhere I saw a default of 5 mentioned for Imagick (although I didn't find the code), perhaps it is readable so I will try to check it. Still if quality isn't adversely affected, probably worth raising given the very slow encoding speed.

https://imagemagick.org/script/defines.php

heic:speed=value	set the HEIC speed parameter. Integer value from 0-9. Default is 5.

It would be good to verify this though.

@adamsilverstein
Copy link
Member

It would be good to verify this though.

I couldn't find the default anywhere in the codebase, but I did see a 22% speed improvement when explicitly setting the speed variable to 7 (comments on the PR). I can re-test with 5 to verify this is the same speed as not setting a speed - this will confirm the default.

In the meantime, I plan to resume work here on the PNG -> AVIF/WebP conversion support.

@adamsilverstein adamsilverstein removed the Needs Discussion Anything that needs a discussion/agreement label Jul 31, 2024
@adamsilverstein
Copy link
Member

I created a PR that adds PNG upload to AVIF (or WebP) output - #1421

@adamsilverstein adamsilverstein self-assigned this Aug 5, 2024
@adamsilverstein adamsilverstein moved this from In Progress 🚧 to Code Review 👀 in WP Performance 2024 Aug 8, 2024
@github-project-automation github-project-automation bot moved this from Code Review 👀 to Done 😃 in WP Performance 2024 Sep 4, 2024
@chrillep
Copy link

chrillep commented Sep 6, 2024

@mukeshpanchal27 friday release? 🤠

@swissspidy
Copy link
Member

The next Performance Lab release is planned for the week after WordCamp US. See https://make.wordpress.org/core/2024/09/03/performance-chat-summary-03-september-2024/

@westonruter
Copy link
Member

@chrillep You can still use a pre-release version of the plugin though. I just created a build via npm run build-plugins:zip: webp-uploads.zip

Your early testing and feedback would be much appreciated!

@benoitfouc
Copy link

@chrillep You can still use a pre-release version of the plugin though. I just created a build via npm run build-plugins:zip: webp-uploads.zip

Your early testing and feedback would be much appreciated!

Thank you very much, i make some tests with your file and all is working good for me :) 🚀

@desrosj
Copy link
Contributor

desrosj commented Nov 12, 2024

@jzern While compiling a list of contributors that helped with the upcoming WordPress 6.7 release using the project's "Prop" script, your account came up as not having linked their WordPress.org and GitHub accounts.

In the WordPress project, all credit given out must be attached to a WordPress.org account. After creating a W.org account (or logging in to your preexisting one), you can link your GitHub account following these steps in the Core Handbook. If you could kindly link your .org account and just share your .org username, we can ensure you receive proper attribution! cc/@jeffpaul

@jzern
Copy link

jzern commented Nov 12, 2024

@jzern While compiling a list of contributors that helped with the upcoming WordPress 6.7 release using the project's "Prop" script, your account came up as not having linked their WordPress.org and GitHub accounts.

I signed up for an account, just waiting on the approval to be able to set a password. I didn't really contribute all that much here, so feel free to leave me out if you're about to finalize the release.

@desrosj
Copy link
Contributor

desrosj commented Nov 13, 2024

@jzern All constructive activity deserves recognition and WordPress tries to practice giving props liberally. You gave several tips and suggestions that helped arrive at an eventual solution. 🙂

@jzern
Copy link

jzern commented Nov 19, 2024

I signed up for an account, just waiting on the approval to be able to set a password.

I still haven't seen an email for this. Nothing obvious in spam either. login.wordpress.org says it's still pending.

@jzern
Copy link

jzern commented Nov 19, 2024

I still haven't seen an email for this. Nothing obvious in spam either. login.wordpress.org says it's still pending.

The account is setup now. It's jzern@ and linked to my github account.

@Danrancan
Copy link

@ficod, yeah, I decided to convert them manually with Imagick:

$limit) { $file['error'] = "Image files must be smaller than {$limit}kb"; return $file; } // Get the temporary image path $filepath = $file['tmp_name']; // Get the file's dimensions list($image_width, $image_height) = @getimagesize($filepath); // Calculate the new dimensions for scaling $max_width = ; $max_height = intval($image_height * ($max_width / $image_width)); // Create a new Imagick object from the uploaded image $image = new \Imagick($filepath); // Get original image size $original_size = strlen($image->getImageBlob()); // Check if image already has webp format (do not change quality) if ('image/webp' === $file['type']) { $image->setImageCompressionQuality(100); } else { // Set webp format (support transparency) $image->setImageFormat('webp'); // Set image compression quality $image->setImageCompressionQuality(86); } // Scale down the image to the new dimensions $image->resizeImage(min($image_width, $max_width), min($image_height, $max_height), \Imagick::FILTER_CATROM, 1); // Get resized (webp converted) image size $resized_size = strlen($image->getImageBlob()); // Check if the resized image has a larger file size than the original if ($resized_size >= $original_size) { // Original image has smaller or equal size, so keep it $image->clear(); return $file; } // Save the resized image, overwrite the original file $image->writeImage($filepath); $file['size'] = $resized_size; $image->clear(); // Return result return $file; } add_action('wp_handle_upload_prefilter', __NAMESPACE__ . '\\resize_preupload_image', 10, 1);

Sorry, I'm a noob and just found my way here from google. I am looking to automatically convert images to Afif on a LEMP server. Is this code something I can use to implement this? How can I use it exactly? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Plugin] Modern Image Formats Issues for the Modern Image Formats plugin (formerly WebP Uploads) [Plugin] Performance Lab Issue relates to work in the Performance Lab Plugin only [Type] Enhancement A suggestion for improvement of an existing feature
Projects
Status: Done 😃
Development

Successfully merging a pull request may close this issue.