Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 33 additions & 14 deletions src/wp-admin/includes/image-edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ function _rotate_image_resource( $img, $angle ) {
* Flips an image resource. Internal use only.
*
* @since 2.9.0
* @since 7.2.0 Switched to using imageflip() instead of imagecopyresampled() with negative dimensions.
* @deprecated 3.5.0 Use WP_Image_Editor::flip()
* @see WP_Image_Editor::flip()
*
Expand All @@ -577,25 +578,43 @@ function _rotate_image_resource( $img, $angle ) {
function _flip_image_resource( $img, $horz, $vert ) {
_deprecated_function( __FUNCTION__, '3.5.0', 'WP_Image_Editor::flip()' );

$w = imagesx( $img );
$h = imagesy( $img );
$dst = wp_imagecreatetruecolor( $w, $h );
if ( ! is_gd_image( $img ) ) {
return $img;
}

if ( is_gd_image( $dst ) ) {
$sx = $vert ? ( $w - 1 ) : 0;
$sy = $horz ? ( $h - 1 ) : 0;
$sw = $vert ? -$w : $w;
$sh = $horz ? -$h : $h;
// Keep returning a truecolor image, like the previous implementation did. imagewebp() rejects palette images.
if ( ! imageistruecolor( $img ) && ! imagepalettetotruecolor( $img ) ) {
return $img;
}

if ( imagecopyresampled( $dst, $img, 0, 0, $sx, $sy, $w, $h, $sw, $sh ) ) {
if ( PHP_VERSION_ID < 80000 ) { // imagedestroy() has no effect as of PHP 8.0.
imagedestroy( $img );
}
// Match the alpha settings of the previous implementation's copy, including when no axis is flipped.
imagealphablending( $img, false );
imagesavealpha( $img, true );
Comment thread
desrosj marked this conversation as resolved.
Resolved

$img = $dst;
}
/*
* imageflip() changes the image in place, so the image keeps its current resolution and interlace setting.
* _rotate_image_resource() and _crop_image_resource() copy into a new image, which resets them to GD's defaults:
* 96 DPI and no interlacing. Reset them here too, so a flip gives the same result as the other edits.
*
* @link https://core.trac.wordpress.org/ticket/66113
*/
imageresolution( $img, 96, 96 );
imageinterlace( $img, 0 );

if ( ! $horz && ! $vert ) {
return $img;
}

if ( $horz && $vert ) {
$mode = IMG_FLIP_BOTH;
} elseif ( $horz ) {
$mode = IMG_FLIP_VERTICAL;
} else {
$mode = IMG_FLIP_HORIZONTAL;
}

imageflip( $img, $mode );

return $img;
}

Expand Down
58 changes: 43 additions & 15 deletions src/wp-includes/class-wp-image-editor-gd.php
Original file line number Diff line number Diff line change
Expand Up @@ -432,31 +432,59 @@ public function rotate( $angle ) {
* Flips current image.
*
* @since 3.5.0
* @since 7.2.0 Switched to using imageflip() instead of imagecopyresampled() with negative dimensions.
*
* @param bool $horz Flip along Horizontal Axis.
* @param bool $vert Flip along Vertical Axis.
* @return true|WP_Error
*/
public function flip( $horz, $vert ) {
$w = $this->size['width'];
$h = $this->size['height'];
$dst = wp_imagecreatetruecolor( $w, $h );
if ( ! is_gd_image( $this->image ) ) {
return new WP_Error( 'image_flip_error', __( 'Image flip failed.' ), $this->file );
}

if ( is_gd_image( $dst ) ) {
$sx = $vert ? ( $w - 1 ) : 0;
$sy = $horz ? ( $h - 1 ) : 0;
$sw = $vert ? -$w : $w;
$sh = $horz ? -$h : $h;
/*
* imageflip() works in place and keeps palette images as palette images.
* The previous implementation always copied into a new truecolor image,
* and saving or streaming as WebP relies on that, since imagewebp()
* rejects palette images. Convert first to keep that behavior.
*/
if ( ! imageistruecolor( $this->image ) && ! imagepalettetotruecolor( $this->image ) ) {
return new WP_Error( 'image_flip_error', __( 'Image flip failed.' ), $this->file );
}

if ( imagecopyresampled( $dst, $this->image, 0, 0, $sx, $sy, $w, $h, $sw, $sh ) ) {
if ( PHP_VERSION_ID < 80000 ) { // imagedestroy() has no effect as of PHP 8.0.
imagedestroy( $this->image );
}
/*
* imageflip() also keeps the current alpha settings, which rotate() leaves
* with blending enabled. Reset them to what the previous implementation
* always produced, including when no axis is flipped.
*/
imagealphablending( $this->image, false );
imagesavealpha( $this->image, true );

Comment thread
desrosj marked this conversation as resolved.
Resolved
$this->image = $dst;
/*
* imageflip() changes the image in place, so the image keeps its current resolution and interlace setting.
* rotate(), crop() and resize() copy into a new image, which resets them to GD's defaults: 96 DPI and no
* interlacing. Reset them here too, so a flip gives the same result as the other edits.
*
* @link https://core.trac.wordpress.org/ticket/66113
*/
imageresolution( $this->image, 96, 96 );
imageinterlace( $this->image, 0 );

return true;
}
if ( ! $horz && ! $vert ) {
return true;
}

if ( $horz && $vert ) {
$mode = IMG_FLIP_BOTH;
} elseif ( $horz ) {
$mode = IMG_FLIP_VERTICAL;
} else {
$mode = IMG_FLIP_HORIZONTAL;
}

if ( imageflip( $this->image, $mode ) ) {
return true;
}

return new WP_Error( 'image_flip_error', __( 'Image flip failed.' ), $this->file );
Expand Down
Loading
Loading