Make WordPress Core

Opened 5 weeks ago

Closed 3 weeks ago

Last modified 3 weeks ago

#62331 closed defect (bug) (fixed)

Image editing in GD runs image stream functions multiple times

Reported by: glynnquelch's profile glynnquelch Owned by: adamsilverstein's profile adamsilverstein
Milestone: 6.7.1 Priority: normal
Severity: normal Version: 6.5
Component: Media Keywords: has-patch fixed-major commit dev-reviewed
Focuses: Cc:

Description

I referenced this on a similar issue
https://core.trac.wordpress.org/ticket/23127#comment:29

When the imagecreatefromstring() function is called in wp-includes/class-wp-image-editor-gd.php, it will often call this function twice. This often results in serious memory issues for larger images and at some formats it doubles the memory used

<?php
// WebP may not work with imagecreatefromstring().
if (
 function_exists( 'imagecreatefromwebp' ) &&
 ( 'image/webp' === wp_get_image_mime( $this->file ) )
) {
 $this->image = @imagecreatefromwebp( $this->file );
} else {
 $this->image = @imagecreatefromstring( $file_contents );
}

// AVIF may not work with imagecreatefromstring().
if (
 function_exists( 'imagecreatefromavif' ) &&
 ( 'image/avif' === wp_get_image_mime( $this->file ) )
) {
 $this->image = @imagecreatefromavif( $this->file );
} else {
 $this->image = @imagecreatefromstring( $file_contents );
}

If I make a change locally to

<?php
// WebP may not work with imagecreatefromstring().
if ( function_exists( 'imagecreatefromwebp' ) &&
        ( 'image/webp' === wp_get_image_mime( $this->file ) )
) {
        $this->image = @imagecreatefromwebp( $this->file );
// AVIF may not work with imagecreatefromstring().
} elseif ( function_exists( 'imagecreatefromavif' ) &&
        ( 'image/avif' === wp_get_image_mime( $this->file ) )
) {
        $this->image = @imagecreatefromavif( $this->file );
} else {
        $this->image = @imagecreatefromstring( $file_contents );
}

I see a reduction in the memory overhead

Filename Size (W x H) Filesize Current GD Peak Memory Improved Flow Peak Memory
Suru_Bog_10000px.jpg10000 x 453433.08 MB410.41 MB266 MB
test.jpg7500 x 75001.75 MB510.02 MB308.71 MB
156442-ultra-widescreen-wallpaper.jpg4500 x 1901642.36 KB96.98 MB92.96 MB
logo.png1024 x 51285.47 KB20.36 MB10.29 MB
Sample-10345x5531.webp10345 x 39897.49MB378.79 MB207.38MB
minion-large.webp10000 x 50002.15MB419.38 MB224.05MB
minion-large.gif25000 x 1250025.84MB734.04 MB424.89MB
SamplePNGImage_30mbmb.png7345 x 283231.39MB297.11 MB241.41MB
IMG_20211115_123549.jpg4624 x 34722.57 MB167.69 MB132.58MB

Some smaller images see no difference and some gifs use more memory at times, but for images with larger dimensions, we see memory allocation errors with hosts that limit memory at 512mb of ram.

Attachments (1)

62331.diff (1.1 KB) - added by glynnquelch 5 weeks ago.
Diff to improve the control flow

Download all attachments as: .zip

Change History (18)

@glynnquelch
5 weeks ago

Diff to improve the control flow

#1 @desrosj
5 weeks ago

  • Keywords has-patch needs-testing added; needs-patch removed
  • Milestone changed from Awaiting Review to 6.7.1

Thanks for this report, @glynnquelch. And welcome to Trac!

Unfortunately, it’s too late to consider this for 6.7, but this sort of thing would be great to improve as soon as we’re able to validate and test properly.

Moving to 6.7.1 for investigation.

#2 @adamsilverstein
5 weeks ago

  • Version changed from trunk to 6.5

Good catch @glynnquelch and thanks for the new ticket - the logic there does look incorrect. It was fine when we added the original conditional when WebP was introduced. When we added AVIF support we should added the else logic as you have it. Marking this as having originated in 6.5.

#3 @adamsilverstein
5 weeks ago

  • Owner set to adamsilverstein
  • Status changed from new to assigned

#5 @adamsilverstein
5 weeks ago

Tests for patch running on https://github.com/WordPress/wordpress-develop/pull/7705 (also adds consolidating comment lines).

It would be nice to add a unit test for this, ideally asserting that imagecreatefromstring is only called once.

This is a pretty significant bug for GD users and a very small change to fix: we may want to consider back porting to 6.5+.

#6 @adamsilverstein
5 weeks ago

It would be nice to add a unit test for this, ideally asserting that imagecreatefromstring is only called once.

Not sure this is possible with our testing framework. Fortunately, the fix is clear looking at the code logic. Previous to the this change, imagecreatefromstring is called twice.

#7 @glynnquelch
5 weeks ago

Thanks for running with this @adamsilverstein 🚀🙌

This ticket was mentioned in Slack in #core by desrosj. View the logs.


3 weeks ago

#9 @desrosj
3 weeks ago

Because of a few bug reports opened since 6.7 was released, the Core team is evaluating the need for a short 6.7.1 cycle (possibly next week).

While this issue was not introduced during 6.7 (which technically means it now falls outside of the focus for 6.7.1 as currently defined), I think this is worth including. As @adamsilverstein said, this is a pretty significant bug for GD users, and there are likely some undiscovered edge cases from running WebP images through imagecreatefromstring).

#10 @desrosj
3 weeks ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 59413:

Media: Avoid running expensive logic twice using GD.

Support for uploading AVIF was added in [57524]. A new block of conditional logic was added determine which function should be used to create the new image file that resulted in these expensive functions being run twice.

This combines the two conditional logic to ensure the appropriate function is only run once regardless of format.

Props adamsilverstein, glynnquelch.
Fixes #62331.

#11 @desrosj
3 weeks ago

  • Keywords fixed-major added
  • Resolution fixed deleted
  • Status changed from closed to reopened

Reopening to consider backporting.

#12 @desrosj
3 weeks ago

  • Keywords dev-feedback commit added

Properly marking for backport review.

#13 @adamsilverstein
3 weeks ago

Looks good for backporting @desrosj - thanks!

This ticket was mentioned in Slack in #core by desrosj. View the logs.


3 weeks ago

#15 @desrosj
3 weeks ago

  • Keywords dev-reviewed added; needs-testing dev-feedback removed

Thank you!

#16 @desrosj
3 weeks ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 59423:

Media: Avoid running expensive logic twice using GD.

Support for uploading AVIF was added in [57524]. A new block of conditional logic was added determine which function should be used to create the new image file that resulted in these expensive functions being run twice.

This combines the two conditional logic to ensure the appropriate function is only run once regardless of format.

Reviewed by adamsilverstein.
Merges [59413] to the 6.7 branch.

Props adamsilverstein, glynnquelch.
Fixes #62331.

#17 @desrosj
3 weeks ago

  • Summary changed from Imaged Edit GD Control Flow to Image editing in GD runs image stream functions multiple times
Note: See TracTickets for help on using tickets.