performance icon indicating copy to clipboard operation
performance copied to clipboard

PNG conversion to AVIF / WebP does not work reliably

Open felixarntz opened this issue 10 months ago • 14 comments

Bug Description

When I uploaded a PNG to my website in the block editor, I ran into a problem where the image file would not be found. As the file was (supposed to be) transformed to AVIF, I suspected it might have something to do with the Modern Image Formats plugin. Indeed that appears to be the case.

Some more details on what I am experiencing:

  • The thumbnail file {orig-name}-150x150.avif was successfully generated. But the main attachment file {orig-name}-png.avif is not to be found.
  • To test, I changed the target format option from "AVIF" to "WebP". After doing that, the same file doesn't get transformed at all. Obviously better than a broken image, but it's just as strange that the WebP transformation doesn't appear to even occur in this case.
  • I'm seeing the warning in Site Health that "Your site does not send AVIF image headers correctly". Could that be causing it? If that's the case and we already detect it though, we should probably not be generating AVIF.
  • It's strange that this happened, because literally a minute before I had uploaded another PNG image which was transformed into AVIF without any issues. So it's not consistent, but definitely seems unreliable.

There is a chance this has to do with certain server support / configuration, but in any case we should try to figure it out since we shouldn't offer transforming to AVIF in situations where it's not reliable.

Possibly caused by addition of PNG support which was done via #371. I don't have any problems with transforming JPEG into AVIF or WebP, the problems only occur with PNG files.

Steps to reproduce

  1. Make sure the plugin is set to transform into AVIF.
  2. Make sure generating fallback formats is off.
  3. Either edit a post in the block editor and upload a PNG image. Or upload a PNG image directly to the media library.

Additional Context

  • PHP Version: 8.1
  • WordPress Version: 6.7.1
  • OS: Mac OS
  • Browser: Chrome
  • Plugin Version: 2.4.0

felixarntz avatar Jan 13 '25 22:01 felixarntz

@adamsilverstein Any idea what might be going on here?

felixarntz avatar Jan 13 '25 22:01 felixarntz

@adamsilverstein Any idea what might be going on here?

Could it possibly be related to the PNG itself? ie. does one PNG consistently fail to generate sub sizes while another consistently works? Can you check server logs and the browser console log for any potential errors?

I can give this a test to see if I can reproduce on my end

adamsilverstein avatar Jan 13 '25 22:01 adamsilverstein

@adamsilverstein I can confirm it always happens with specific PNG images, but not others. So there has to be something maybe in the different PNG encodings that makes my server not want to deal with some of them.

There are no errors or Console logs when uploading them. So the problem isn't flagged, it's "silently" failing. When I try to open the full size image (for one of the PNG uploads where the problem occurs), I just get a 404.

felixarntz avatar Jan 14 '25 16:01 felixarntz

I can confirm it always happens with specific PNG images, but not others.

Could be related to alpha channel presence, transparency or bit depth.

Can you share your site health->info->media details so we can see what version GD/Imagick you are using?

If possible, can you share a working and non-working image? these would be useful for a unit test to reproduce the issue.

We recently landed some PNG handling improvements in core that could help, if possible can you try agains trunk?

adamsilverstein avatar Jan 14 '25 17:01 adamsilverstein

Possibly your generated images are larger that the original and so is being discarded in webp_uploads_should_discard_additional_image_file.

Do you have the "Also generate fallback images in the original upload format" option enabled under settings->media? If so, try disabling that to see if generation works for all images.

If you want both images always, you can disable the deletion behavior with:

add_filter( 'webp_uploads_discard_larger_generated_images', '__return_false' );

adamsilverstein avatar Jan 14 '25 17:01 adamsilverstein

Here's my Site Health info for media:

image_editor: WP_Image_Editor_Imagick
imagick_module_version: 1693
imagemagick_version: ImageMagick 6.9.13-17 Q16 x86_64 18482 https://legacy.imagemagick.org
imagick_version: 3.7.0
file_uploads: 1
post_max_size: 100M
upload_max_filesize: 100M
max_effective_size: 100 MB
max_file_uploads: 50
imagick_limits: 
	imagick::RESOURCETYPE_AREA: 503 GB
	imagick::RESOURCETYPE_DISK: 9.2233720368548E+18
	imagick::RESOURCETYPE_FILE: 24576
	imagick::RESOURCETYPE_MAP: 252 GB
	imagick::RESOURCETYPE_MEMORY: 126 GB
	imagick::RESOURCETYPE_THREAD: 1
	imagick::RESOURCETYPE_TIME: 0
imagemagick_file_formats: 3FR, 3G2, 3GP, AAI, AI, APNG, ART, ARW, AVI, 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, DOT, DPX, DXT1, DXT5, EPDF, EPI, EPS, EPS2, EPS3, EPSF, EPSI, EPT, EPT2, EPT3, ERF, EXR, FAX, FILE, FITS, FLV, FRACTAL, FTP, FTS, G3, G4, GIF, GIF87, GRADIENT, GRAY, GRAYA, GROUP4, GV, H, HALD, HDR, 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, MPEG, MPG, MRW, MSL, MSVG, MTV, MVG, NEF, NRW, NULL, ORF, OTB, OTF, PAL, PALM, PAM, PANGO, 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, SVG, SVGZ, TEXT, TGA, THUMBNAIL, TIFF, TIFF64, TILE, TIM, TTC, TTF, TXT, UBRL, UBRL6, UIL, UYVY, VDA, VICAR, VID, VIDEO, VIFF, VIPS, VST, WBMP, WEBM, WEBP, WMF, WMV, WMZ, WPG, X, X3F, XBM, XC, XCF, XPM, XPS, XV, XWD, YCbCr, YCbCrA, YUV
gd_version: bundled (2.1.0 compatible)
gd_formats: GIF, JPEG, PNG, WebP, BMP, AVIF, XPM
ghostscript_version: 9.27

It looks like my site's Imagemagick version does not support AVIF, but GD does, so I assume my site attempts to use GD for AVIF.

felixarntz avatar Jan 14 '25 18:01 felixarntz

Do you have the "Also generate fallback images in the original upload format" option enabled under settings->media? If so, try disabling that to see if generation works for all images.

That option is turned off on my site, so I have the problem even with the (technically much simpler) setup of only mapping the output format.

felixarntz avatar Jan 14 '25 18:01 felixarntz

This might be related to a GD "false positive" issue, see https://core.trac.wordpress.org/ticket/60628 which mentions zero sized image failures for some GD versions (although its odd that some sizes work).

Can you try to determine your PHP / GD versions and maybe see if you are able to get them upgraded or get imagick installed by your host?

adamsilverstein avatar Jan 15 '25 21:01 adamsilverstein

Aside: Since the PNG to AVIF generation only fails for the original image, but not the thumbnail, I wonder whether any of the additional processing of the sub-sizes (e.g. scaling down the image) alters something in the PNG file already, which then makes the conversion to AVIF work.

Since only the originally uploaded image is failing to convert to AVIF (which of course is completely outside of WordPress's control in terms of how it's encoded etc.), I wonder whether it would work if we first did some other (temporary) processing to that image before saving it as AVIF.

felixarntz avatar Jan 15 '25 21:01 felixarntz

Since only the originally uploaded image is failing to convert to AVIF (which of course is completely outside of WordPress's control in terms of how it's encoded etc.), I wonder whether it would work if we first did some other (temporary) processing to that image before saving it as AVIF.

Maybe - we can certainly try retracing the calls more carefully and trying to reproduce. One thing I noticed is we do call resize on the image, but the image dimensions match those of the original, so that call returns early (this conditional returns true). We could try calling with a slightly different size to test.

adamsilverstein avatar Jan 15 '25 22:01 adamsilverstein

@felixarntz this may be related to a flaw in core's PNG processing where it explicitly skips the largest size without considering the output format, see https://core.trac.wordpress.org/ticket/62900. Possibly this logic should be remoived entirely, but for now I have made it so it only applies when PNG is both input and output format. Can you see if the linked PR there resolves the issue you reported here?

adamsilverstein avatar Feb 05 '25 14:02 adamsilverstein

@adamsilverstein I don't think the issue here would be addressed by that PR. It's probably a different bug because in my case I do get an AVIF version for the file, but it's not found, and it's inconsistent.

There is a good chance it's related though, so it's a good catch. Maybe this image/png exclusion for big images is there for a reason, maybe it's unstable or too resource/time intensive to be reliable, and that's related to the inconsistency in the bug here.

It may also point to a problem in the Modern Image Formats plugin where maybe we assume that every image exists in the converted format, even though in a scenario like this the original image wouldn't be converted. Worth investigating further...

felixarntz avatar Feb 05 '25 21:02 felixarntz

Maybe this image/png exclusion for big images is there for a reason, maybe it's unstable or too resource/time intensive to be reliable

The original reason appears to be that the output image is larger than the input image, however this may have been caused by a bug where 8 bit pngs were output as 24 bit pngs.

It may also point to a problem in the Modern Image Formats plugin where maybe we assume that every image exists in the converted format, even though in a scenario like this the original image wouldn't be converted.

This shouldn't happen because we store each image generated in meta as we generate them. when we build out srcset we only include images that in the meta data (although possibly some assumptions are made for the full size/original image?)

adamsilverstein avatar Feb 06 '25 16:02 adamsilverstein

Hi, I can confirm that this issue also occurs in my case, both with and without the Modern Image Formats plugin, but using the function below.

  function custom_filter_image_editor_output_format($formats) {
    $formats['image/jpeg'] = 'image/avif';
    $formats['image/webp'] = 'image/avif';
    $formats['image/png'] = 'image/avif';
    return $formats;
  }
  add_filter('image_editor_output_format', 'custom_filter_image_editor_output_format');

Image

gyurmey2 avatar Feb 08 '25 16:02 gyurmey2

@felixarntz I tried to replicate this issue on my end, and it is very random; sometimes it works fine, and sometimes it does not for the same images, but most of the time it is working fine. I tried with large and small PNG images as well. If possible, can you share the image where you are getting this error all the time? Thanks!

Example PNG files:

Small Image: Image

Large Images:

Image

Image


@gyurmey2 I tried with the snippet you shared, the images are uploading and converting fine for me with or without your snippet, the only difference is that when I have added your snippet, the file name is not adding extension at the end of the file name, like:

  • Original file name: PNG_1MB.png
  • Without your snippet, new file name: PNG_1MB-png.avif
  • With your snippet, new file name: PNG_1MB.avif

@gyurmey2 If possible, can you share the images which you are testing with? Thanks!

vishalkakadiya avatar May 06 '25 05:05 vishalkakadiya

@vishalkakadiya I can't reproduce this issue now, so it looks like it has been fixed. 🤔

gyurmey2 avatar May 16 '25 09:05 gyurmey2

Thanks for the detailed write-up — this does sound like a tricky case tied to server support or inconsistent header behavior.

In the meantime, if you need a quick workaround to manually convert PNGs to AVIF (or back), https://aviftools.com/ is a handy browser-based tool. No installation or login required — could be useful for testing or uploading preconverted images when plugin behavior is unpredictable.

Hope this gets resolved in the next release!

pqmpqm123 avatar Jul 18 '25 09:07 pqmpqm123

In the meantime, if you need a quick workaround to manually convert PNGs to AVIF (or back), https://aviftools.com/ is a handy browser-based tool. No installation or login required — could be useful for testing or uploading preconverted images when plugin behavior is unpredictable.

That would work for the primary image, but ideally you want WordPress to create the sub-sized images used for the srcset attribute on the front end. Without working AVIF support on the server you can't currently get that.

adamsilverstein avatar Jul 19 '25 00:07 adamsilverstein

I think this might be related and I can consistently reproduce the issue by running the png through pngquant. I'm not sure how to get WordPress Studio to support AVIF or I would have done some additional debugging.

Issue Uploading certain PNG files result in a 0-byte AVIF image for the original size but the resized versions are fine.

To reproduce

  1. Set "Image output format" to AVIF in the Modern Image Formats settings (WP_Image_Editor_GD)
  2. Run the PNG through pngquant (I used the command line version on macOS)
  3. Upload file created by pngquant

Original image that works Image

Image run through pngquant that turns into 0 bytes Image

> file test-file.png
test-file.png: PNG image data, 200 x 50, 8-bit/color RGB, non-interlaced

> file test-file-pngquant.png
test-file-pngquant.png: PNG image data, 200 x 50, 8-bit colormap, non-interlaced

Using exiftool there are a couple of differences:

Original

File Size                       : 1030 bytes
Color Type                      : RGB

pngquant

File Size                       : 561 bytes
Color Type                      : Palette
Palette                         : (Binary data 51 bytes, use -b option to extract)

Could the RGB / colormap / color palette difference be what's creating problems for the conversion?

iamjohnford avatar Jul 24 '25 20:07 iamjohnford

@iamjohnford The issue you are referring to could be caused by palette-based PNG, which will be fixed by #2024. For more details, see #2018.

b1ink0 avatar Aug 19 '25 09:08 b1ink0

@felixarntz - are you still able to reproduce the issue after the fix in https://github.com/WordPress/performance/pull/2024?

adamsilverstein avatar Aug 31 '25 23:08 adamsilverstein

Thanks! Looks like the latest version (2.6.0) fixed our issue.

iamjohnford avatar Aug 31 '25 23:08 iamjohnford