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
27 changes: 11 additions & 16 deletions src/wp-admin/includes/image-edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -577,25 +577,20 @@ 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( $dst ) ) {
$sx = $vert ? ( $w - 1 ) : 0;
$sy = $horz ? ( $h - 1 ) : 0;
$sw = $vert ? -$w : $w;
$sh = $horz ? -$h : $h;

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 );
}
if ( ! is_gd_image( $img ) || ( ! $horz && ! $vert ) ) {
return $img;
}

$img = $dst;
}
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
29 changes: 12 additions & 17 deletions src/wp-includes/class-wp-image-editor-gd.php
Original file line number Diff line number Diff line change
Expand Up @@ -438,25 +438,20 @@ public function rotate( $angle ) {
* @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( $dst ) ) {
$sx = $vert ? ( $w - 1 ) : 0;
$sy = $horz ? ( $h - 1 ) : 0;
$sw = $vert ? -$w : $w;
$sh = $horz ? -$h : $h;

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 );
}
if ( ! $horz && ! $vert ) {
return true;
}

$this->image = $dst;
if ( $horz && $vert ) {
$mode = IMG_FLIP_BOTH;
} elseif ( $horz ) {
$mode = IMG_FLIP_VERTICAL;
} else {
$mode = IMG_FLIP_HORIZONTAL;
}

return true;
}
if ( is_gd_image( $this->image ) && imageflip( $this->image, $mode ) ) {
return true;
Comment on lines +453 to +454

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this image check happens after the early return for the dimensions, an invalid image that's passed will never be flagged when dimensions are empty.

In my opinion, it's preferable to flag the more severe issue first. The dimensions do not matter if the image is invalid or empty.

}

return new WP_Error( 'image_flip_error', __( 'Image flip failed.' ), $this->file );
Expand Down
153 changes: 153 additions & 0 deletions tests/phpunit/tests/image/editorGd.php
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,159 @@ public function test_flip() {
$this->assertSame( $color_top_left, imagecolorat( $property->getValue( $gd_image_editor ), 0, 99 ) );
}

/**
* Tests that flipping moves every pixel to the expected position.
*
* @ticket 66113
*
* @dataProvider data_flip
*
* @covers WP_Image_Editor_GD::flip
*
* @param bool $horz Whether to flip along the horizontal axis.
* @param bool $vert Whether to flip along the vertical axis.
*/
public function test_flip_moves_pixels( $horz, $vert ) {
$gd_image_editor = new WP_Image_Editor_GD( DIR_TESTDATA . '/images/gradient-square.jpg' );
$gd_image_editor->load();

$property = new ReflectionProperty( $gd_image_editor, 'image' );
if ( PHP_VERSION_ID < 80100 ) {
$property->setAccessible( true );
}

// A 3x2 image in which every pixel has a distinct color.
$width = 3;
$height = 2;
$image = imagecreatetruecolor( $width, $height );
for ( $x = 0; $x < $width; $x++ ) {
for ( $y = 0; $y < $height; $y++ ) {
imagesetpixel( $image, $x, $y, ( $x + 1 ) * 0x100000 + ( $y + 1 ) * 0x10 );
}
}
$original = imagecreatetruecolor( $width, $height );
imagecopy( $original, $image, 0, 0, 0, 0, $width, $height );

$property->setValue( $gd_image_editor, $image );

$size_property = new ReflectionProperty( $gd_image_editor, 'size' );
if ( PHP_VERSION_ID < 80100 ) {
$size_property->setAccessible( true );
}
$size_property->setValue(
$gd_image_editor,
array(
'width' => $width,
'height' => $height,
)
);

$this->assertTrue( $gd_image_editor->flip( $horz, $vert ), 'flip() should return true on success.' );

$flipped = $property->getValue( $gd_image_editor );
for ( $x = 0; $x < $width; $x++ ) {
for ( $y = 0; $y < $height; $y++ ) {
$this->assertSame(
imagecolorat( $original, $x, $y ),
imagecolorat( $flipped, $vert ? $width - 1 - $x : $x, $horz ? $height - 1 - $y : $y ),
"Pixel ($x, $y) was not moved to the expected position."
);
}
}
}

/**
* Tests that the deprecated _flip_image_resource() moves every pixel to the expected position.
*
* @ticket 66113
*
* @dataProvider data_flip
*
* @covers ::_flip_image_resource
*
* @expectedDeprecated _flip_image_resource
*
* @param bool $horz Whether to flip along the horizontal axis.
* @param bool $vert Whether to flip along the vertical axis.
*/
public function test_flip_image_resource_moves_pixels( $horz, $vert ) {
require_once ABSPATH . 'wp-admin/includes/image-edit.php';

// A 3x2 image in which every pixel has a distinct color.
$width = 3;
$height = 2;
$image = imagecreatetruecolor( $width, $height );
for ( $x = 0; $x < $width; $x++ ) {
for ( $y = 0; $y < $height; $y++ ) {
imagesetpixel( $image, $x, $y, ( $x + 1 ) * 0x100000 + ( $y + 1 ) * 0x10 );
}
}
$original = imagecreatetruecolor( $width, $height );
imagecopy( $original, $image, 0, 0, 0, 0, $width, $height );

$flipped = _flip_image_resource( $image, $horz, $vert );

$this->assertTrue( is_gd_image( $flipped ), '_flip_image_resource() should return a GD image.' );
for ( $x = 0; $x < $width; $x++ ) {
for ( $y = 0; $y < $height; $y++ ) {
$this->assertSame(
imagecolorat( $original, $x, $y ),
imagecolorat( $flipped, $vert ? $width - 1 - $x : $x, $horz ? $height - 1 - $y : $y ),
"Pixel ($x, $y) was not moved to the expected position."
);
}
}
}

/**
* Tests that flipping returns a WP_Error, not false, when the image cannot be flipped.
*
* @ticket 66113
*
* @covers WP_Image_Editor_GD::flip
*/
public function test_flip_returns_wp_error_on_failure() {
$gd_image_editor = new WP_Image_Editor_GD( DIR_TESTDATA . '/images/gradient-square.jpg' );
$gd_image_editor->load();

$property = new ReflectionProperty( $gd_image_editor, 'image' );
if ( PHP_VERSION_ID < 80100 ) {
$property->setAccessible( true );
}
$property->setValue( $gd_image_editor, false );

$result = $gd_image_editor->flip( true, false );

$this->assertWPError( $result, 'flip() should return a WP_Error on failure.' );
$this->assertSame( 'image_flip_error', $result->get_error_code(), 'The error code should be image_flip_error.' );
}

/**
* Data provider.
*
* @return array<string, array{ horz: bool, vert: bool }>
*/
public function data_flip() {
return array(
'horizontal axis' => array(
'horz' => true,
'vert' => false,
),
'vertical axis' => array(
'horz' => false,
'vert' => true,
),
'both axes' => array(
'horz' => true,
'vert' => true,
),
'neither axis' => array(
'horz' => false,
'vert' => false,
),
);
}

/**
* Tests that an image created with WP_Image_Editor_GD preserves alpha with no resizing.
*
Expand Down
Loading