Make WordPress Core


Ignore:
Timestamp:
11/10/2026 01:33:13 AM (23 hours ago)
Author:
desrosj
Message:

Media: Use imageflip() to flip images with GD.

WP_Image_Editor_GD::flip() and the deprecated _flip_image_resource() mirrored images by copying them with imagecopyresampled() and negative source dimensions. With the GD 2.4.0 bundled in PHP 8.6, this produces an all-black image. It affects flips in the image editor, and also JPEG uploads with an EXIF orientation of 2, 3 or 4, which WP_Image_Editor::maybe_exif_rotate() flips.

Both functions now flip the image in place with imageflip(), and the output stays the same as before. Palette images are still converted to truecolor, alpha blending is turned off and alpha saving on, and the resolution and interlacing are reset to GD's defaults of 96 DPI and off. This matches what rotate(), crop() and resize() produce. Whether every operation should keep the source image's resolution and interlacing will be decided in a follow-up ticket.

When no valid image is loaded, flip() now returns a WP_Error instead of throwing a TypeError.

Props sanjith2023, rumancodes, arshidkv12, dhruvang21, abhishekfdd, desrosj.
Fixes #66113.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/image-edit.php

    r63002 r65367  
    566566 *
    567567 * @since 2.9.0
     568 * @since 7.2.0 Switched to using imageflip() instead of imagecopyresampled() with negative dimensions.
    568569 * @deprecated 3.5.0 Use WP_Image_Editor::flip()
    569570 * @see WP_Image_Editor::flip()
    … …  
    578579        _deprecated_function( __FUNCTION__, '3.5.0', 'WP_Image_Editor::flip()' );
    579580
    580         $w   = imagesx( $img );
    581         $h   = imagesy( $img );
    582         $dst = wp_imagecreatetruecolor( $w, $h );
    583 
    584         if ( is_gd_image( $dst ) ) {
    585                 $sx = $vert ? ( $w - 1 ) : 0;
    586                 $sy = $horz ? ( $h - 1 ) : 0;
    587                 $sw = $vert ? -$w : $w;
    588                 $sh = $horz ? -$h : $h;
    589 
    590                 if ( imagecopyresampled( $dst, $img, 0, 0, $sx, $sy, $w, $h, $sw, $sh ) ) {
    591                         if ( PHP_VERSION_ID < 80000 ) { // imagedestroy() has no effect as of PHP 8.0.
    592                                 imagedestroy( $img );
    593                         }
    594 
    595                         $img = $dst;
    596                 }
    597         }
     581        if ( ! is_gd_image( $img ) ) {
     582                return $img;
     583        }
     584
     585        // Keep returning a truecolor image, like the previous implementation did. imagewebp() rejects palette images.
     586        if ( ! imageistruecolor( $img ) && ! imagepalettetotruecolor( $img ) ) {
     587                return $img;
     588        }
     589
     590        // Match the alpha settings of the previous implementation's copy, including when no axis is flipped.
     591        imagealphablending( $img, false );
     592        imagesavealpha( $img, true );
     593
     594        /*
     595         * imageflip() changes the image in place, so the image keeps its current resolution and interlace setting.
     596         * _rotate_image_resource() and _crop_image_resource() copy into a new image, which resets them to GD's defaults:
     597         * 96 DPI and no interlacing. Reset them here too, so a flip gives the same result as the other edits.
     598         *
     599         * @link https://core.trac.wordpress.org/ticket/66113
     600         */
     601        imageresolution( $img, 96, 96 );
     602        imageinterlace( $img, 0 );
     603
     604        if ( ! $horz && ! $vert ) {
     605                return $img;
     606        }
     607
     608        if ( $horz && $vert ) {
     609                $mode = IMG_FLIP_BOTH;
     610        } elseif ( $horz ) {
     611                $mode = IMG_FLIP_VERTICAL;
     612        } else {
     613                $mode = IMG_FLIP_HORIZONTAL;
     614        }
     615
     616        imageflip( $img, $mode );
    598617
    599618        return $img;
Note: See TracChangeset for help on using the changeset viewer.