WordPress.org

Make WordPress Core

Ticket #34384: 34384.9.diff

File 34384.9.diff, 9.6 KB (added by joemcgill, 4 years ago)
  • src/wp-includes/media.php

    diff --git src/wp-includes/media.php src/wp-includes/media.php
    index 086d50e..1f6d2d4 100644
    function image_make_intermediate_size( $file, $width, $height, $crop = false ) { 
    592592}
    593593
    594594/**
     595 * Helper function to test if aspect ratios for two images match.
     596 *
     597 * @since 4.6.0
     598 *
     599 * @param int $img_a_width  Width of the first image in pixels.
     600 * @param int $img_a_height Height of the first image in pixels.
     601 * @param int $img_b_width  Width of the second image in pixels.
     602 * @param int $img_b_height Height of the second image in pixels.
     603 * @return bool True if aspect ratios match within 1px. False if not.
     604 */
     605function wp_image_matches_ratio( $img_a_width, $img_a_height, $img_b_width, $img_b_height ) {
     606        /*
     607         * To check for varying crops, we calculate the expected size of the smaller
     608         * image if the larger were constrained by the width of the smaller and then
     609         * see if it matches what we're expecting.
     610         */
     611        if ( $img_a_width > $img_b_width ) {
     612                $constrained_size = wp_constrain_dimensions( $img_a_width, $img_a_height, $img_b_width );
     613                $expected_size = array( $img_b_width, $img_b_height );
     614        } else {
     615                $constrained_size = wp_constrain_dimensions( $img_b_width, $img_b_height, $img_a_width );
     616                $expected_size = array( $img_a_width, $img_a_height );
     617        }
     618
     619        // If the image dimensions are within 1px of the expected size, we consider it a match.
     620        $matched = ( abs( $constrained_size[0] - $expected_size[0] ) <= 1 && abs( $constrained_size[1] - $expected_size[1] ) <= 1 );
     621
     622        return $matched;
     623}
     624
     625/**
    595626 * Retrieves the image's intermediate size (resized) path, width, and height.
    596627 *
    597628 * The $size parameter can be an array with the width and height respectively.
    function image_make_intermediate_size( $file, $width, $height, $crop = false ) { 
    623654 *     @type string $file   Image's path relative to uploads directory
    624655 *     @type int    $width  Width of image
    625656 *     @type int    $height Height of image
    626  *     @type string $path   Optional. Image's absolute filesystem path. Only returned if registered
    627  *                          size is passed to `$size` parameter.
    628  *     @type string $url    Optional. Image's URL. Only returned if registered size is passed to `$size`
    629  *                          parameter.
     657 *     @type string $path   Image's absolute filesystem path.
     658 *     @type string $url    Image's URL.
    630659 * }
    631660 */
    632661function image_get_intermediate_size( $post_id, $size = 'thumbnail' ) {
    633         if ( !is_array( $imagedata = wp_get_attachment_metadata( $post_id ) ) )
     662        if ( ! $size || ! is_array( $imagedata = wp_get_attachment_metadata( $post_id ) ) || empty( $imagedata['sizes'] )  ) {
    634663                return false;
     664        }
    635665
    636         // get the best one for a specified set of dimensions
    637         if ( is_array($size) && !empty($imagedata['sizes']) ) {
     666        $data = array();
     667
     668        // Find the best match when '$size' is an array.
     669        if ( is_array( $size ) ) {
    638670                $candidates = array();
    639671
    640672                foreach ( $imagedata['sizes'] as $_size => $data ) {
    641673                        // If there's an exact match to an existing image size, short circuit.
    642674                        if ( $data['width'] == $size[0] && $data['height'] == $size[1] ) {
    643                                 list( $data['width'], $data['height'] ) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
    644 
    645                                 /** This filter is documented in wp-includes/media.php */
    646                                 return apply_filters( 'image_get_intermediate_size', $data, $post_id, $size );
     675                                $candidates[ $data['width'] * $data['height'] ] = $data;
     676                                break;
    647677                        }
    648                         // If it's not an exact match but it's at least the dimensions requested.
     678
     679                        // If it's not an exact match, consider larger sizes with the same aspect ratio.
    649680                        if ( $data['width'] >= $size[0] && $data['height'] >= $size[1] ) {
    650                                 $candidates[ $data['width'] * $data['height'] ] = $_size;
     681                                // If '0' is passed to either size, we test ratios against the original file.
     682                                if ( 0 === $size[0] || 0 === $size[1] ) {
     683                                        $same_ratio = wp_image_matches_ratio( $data['width'], $data['height'], $imagedata['width'], $imagedata['height'] );
     684                                } else {
     685                                        $same_ratio = wp_image_matches_ratio( $data['width'], $data['height'], $size[0], $size[1] );
     686                                }
     687
     688                                if ( $same_ratio ) {
     689                                        $candidates[ $data['width'] * $data['height'] ] = $data;
     690                                }
    651691                        }
    652692                }
    653693
    654694                if ( ! empty( $candidates ) ) {
    655                         // find for the smallest image not smaller than the desired size
    656                         ksort( $candidates );
    657                         foreach ( $candidates as $_size ) {
    658                                 $data = $imagedata['sizes'][$_size];
    659 
    660                                 // Skip images with unexpectedly divergent aspect ratios (crops)
    661                                 // First, we calculate what size the original image would be if constrained to a box the size of the current image in the loop
    662                                 $maybe_cropped = image_resize_dimensions($imagedata['width'], $imagedata['height'], $data['width'], $data['height'], false );
    663                                 // If the size doesn't match within one pixel, then it is of a different aspect ratio, so we skip it, unless it's the thumbnail size
    664                                 if ( 'thumbnail' != $_size &&
    665                                   ( ! $maybe_cropped
    666                                     || ( $maybe_cropped[4] != $data['width'] && $maybe_cropped[4] + 1 != $data['width'] )
    667                                     || ( $maybe_cropped[5] != $data['height'] && $maybe_cropped[5] + 1 != $data['height'] )
    668                                   ) ) {
    669                                   continue;
    670                                 }
    671                                 // If we're still here, then we're going to use this size.
    672                                 list( $data['width'], $data['height'] ) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
    673 
    674                                 /** This filter is documented in wp-includes/media.php */
    675                                 return apply_filters( 'image_get_intermediate_size', $data, $post_id, $size );
     695                        // Sort the array by size if we have more than one candidate.
     696                        if ( 1 < count( $candidates ) ) {
     697                                ksort( $candidates );
    676698                        }
     699
     700                        $data = array_shift( $candidates );
     701                /*
     702                 * When the size requested is smaller than the thumbnail dimensions, we
     703                 * fall back to the thumbnail size to maintain backwards compatibility with
     704                 * pre 4.6 versions of WordPress.
     705                 */
     706                } elseif ( ! empty( $imagedata['sizes']['thumbnail'] ) && $imagedata['sizes']['thumbnail']['width'] >= $size[0] && $imagedata['sizes']['thumbnail']['width'] >= $size[1] ) {
     707                        $data = $imagedata['sizes']['thumbnail'];
     708                } else {
     709                        return false;
    677710                }
     711
     712                // Constrain the width and height attributes to the requested values.
     713                list( $data['width'], $data['height'] ) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
     714
     715        } elseif ( ! empty( $imagedata['sizes'][ $size ] ) ) {
     716                $data = $imagedata['sizes'][ $size ];
    678717        }
    679718
    680         if ( is_array($size) || empty($size) || empty($imagedata['sizes'][$size]) )
     719        // If we still don't have a match at this point, return false.
     720        if ( empty( $data ) ) {
    681721                return false;
     722        }
    682723
    683         $data = $imagedata['sizes'][$size];
    684724        // include the full filesystem path of the intermediate file
    685725        if ( empty($data['path']) && !empty($data['file']) ) {
    686726                $file_url = wp_get_attachment_url($post_id);
    function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attac 
    10921132                        continue;
    10931133                }
    10941134
    1095                 /**
    1096                  * To check for varying crops, we calculate the expected size of the smaller
    1097                  * image if the larger were constrained by the width of the smaller and then
    1098                  * see if it matches what we're expecting.
    1099                  */
    1100                 if ( $image_width > $image['width'] ) {
    1101                         $constrained_size = wp_constrain_dimensions( $image_width, $image_height, $image['width'] );
    1102                         $expected_size = array( $image['width'], $image['height'] );
    1103                 } else {
    1104                         $constrained_size = wp_constrain_dimensions( $image['width'], $image['height'], $image_width );
    1105                         $expected_size = array( $image_width, $image_height );
    1106                 }
    1107 
    11081135                // If the image dimensions are within 1px of the expected size, use it.
    1109                 if ( abs( $constrained_size[0] - $expected_size[0] ) <= 1 && abs( $constrained_size[1] - $expected_size[1] ) <= 1 ) {
     1136                if ( wp_image_matches_ratio( $image_width, $image_height, $image['width'], $image['height'] ) ) {
    11101137                        // Add the URL, descriptor, and value to the sources array to be returned.
    11111138                        $source = array(
    11121139                                'url'        => $image_baseurl . $image['file'],
  • tests/phpunit/tests/image/intermediate_size.php

    diff --git tests/phpunit/tests/image/intermediate_size.php tests/phpunit/tests/image/intermediate_size.php
    index 3808655..09419a2 100644
    class Tests_Image_Intermediate_Size extends WP_UnitTestCase { 
    224224
    225225                $this->assertTrue( strpos( $image['file'], $width . 'x' . $height ) > 0 );
    226226        }
     227
     228        /**
     229         * @ticket 34384
     230         */
     231        public function test_get_intermediate_size_with_small_size_array() {
     232                // Add a hard cropped size that matches the aspect ratio we're going to test.
     233                add_image_size( 'test-size', 200, 100, true );
     234
     235                $file = DIR_TESTDATA . '/images/waffles.jpg';
     236                $id = $this->_make_attachment( $file, 0 );
     237
     238                // Request a size by array that doesn't exist and is smaller than the 'thumbnail'
     239                $image = image_get_intermediate_size( $id, array( 50, 25 ) );
     240
     241                // We should get the 'test-size' file and not the thumbnail.
     242                $this->assertTrue( strpos( $image['file'], '200x100' ) > 0 );
     243        }
     244
     245        /**
     246         * @ticket 34384
     247         */
     248        public function test_get_intermediate_size_with_small_size_array_fallback() {
     249                $file = DIR_TESTDATA . '/images/waffles.jpg';
     250                $id = $this->_make_attachment( $file, 0 );
     251
     252                $original = wp_get_attachment_metadata( $id );
     253                $thumbnail_file = $original['sizes']['thumbnail']['file'];
     254
     255                // Request a size by array that doesn't exist and is smaller than the 'thumbnail'
     256                $image = image_get_intermediate_size( $id, array( 50, 25 ) );
     257
     258                // We should get the 'thumbnail' file as a fallback.
     259                $this->assertSame( $image['file'], $thumbnail_file );
     260        }
    227261}