Make WordPress Core


Ignore:
Timestamp:
05/04/2021 02:43:36 PM (3 years ago)
Author:
adamsilverstein
Message:

Images: enable WebP support.

Add support for uploading, editing and saving WebP images when supported by the server.

Add 'image/webp' to supported mime types. Correctly identify WebP images and sizes even when PHP doesn't support WebP. Resize uploaded WebP files (when supported) and use for front end markup.

Props markoheijne, blobfolio, Clorith, joemcgill, atjn, desrosj, spacedmonkey, marylauc, mikeschroder, hellofromtonya, flixos90.
Fixes #35725.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/media.php

    r50682 r50810  
    49814981 *
    49824982 * @since 5.7.0
     4983 * @since 5.8.0 Added support for WebP images.
    49834984 *
    49844985 * @param string $filename   The file path.
     
    49954996    ) {
    49964997        if ( 2 === func_num_args() ) {
    4997             return getimagesize( $filename, $image_info );
     4998            return _wp_get_image_size( $filename, $image_info );
    49984999        } else {
    4999             return getimagesize( $filename );
     5000            return _wp_get_image_size( $filename );
    50005001        }
    50015002    }
     
    50125013    if ( 2 === func_num_args() ) {
    50135014        // phpcs:ignore WordPress.PHP.NoSilencedErrors
    5014         return @getimagesize( $filename, $image_info );
     5015        return @_wp_get_image_size( $filename, $image_info );
    50155016    } else {
    50165017        // phpcs:ignore WordPress.PHP.NoSilencedErrors
    5017         return @getimagesize( $filename );
    5018     }
    5019 }
     5018        return @_wp_get_image_size( $filename );
     5019    }
     5020}
     5021
     5022/**
     5023 * Extracts meta information about a webp file: width, height and type.
     5024 *
     5025 * @since 5.8.0
     5026 *
     5027 * @param [type] $filename Path to a WebP file.
     5028 * @return array $webp_info {
     5029 *     An array of WebP image information.
     5030 *
     5031 *     @type array $size {
     5032 *         @type int  $width  Image width.
     5033 *         @type int  $height Image height.
     5034 *         @type bool $type   The WebP type: one of 'lossy', 'lossless' or 'animated-alpha'.
     5035 *     }
     5036 */
     5037function wp_get_webp_info( $filename ) {
     5038    $width  = false;
     5039    $height = false;
     5040    $type   = false;
     5041    if ( ! 'image/webp' === wp_get_image_mime( $filename ) ) {
     5042        return compact( 'width', 'height', 'type' );
     5043    }
     5044    try {
     5045        $handle = fopen( $filename, 'rb' );
     5046        if ( $handle ) {
     5047            $magic = fread( $handle, 40 );
     5048            fclose( $handle );
     5049
     5050            // Make sure we got enough bytes.
     5051            if ( strlen( $magic ) < 40 ) {
     5052                return compact( 'width', 'height', 'type' );
     5053            }
     5054
     5055            // The headers are a little different for each of the three formats.
     5056            // Header values based on WebP docs, see https://developers.google.com/speed/webp/docs/riff_container.
     5057            switch ( substr( $magic, 12, 4 ) ) {
     5058                // Lossy WebP.
     5059                case 'VP8 ':
     5060                    $parts  = unpack( 'v2', substr( $magic, 26, 4 ) );
     5061                    $width  = (int) ( $parts[1] & 0x3FFF );
     5062                    $height = (int) ( $parts[2] & 0x3FFF );
     5063                    $type   = 'lossy';
     5064                    break;
     5065                // Lossless WebP.
     5066                case 'VP8L':
     5067                    $parts  = unpack( 'C4', substr( $magic, 21, 4 ) );
     5068                    $width  = (int) ( $parts[1] | ( ( $parts[2] & 0x3F ) << 8 ) ) + 1;
     5069                    $height = (int) ( ( ( $parts[2] & 0xC0 ) >> 6 ) | ( $parts[3] << 2 ) | ( ( $parts[4] & 0x03 ) << 10 ) ) + 1;
     5070                    $type   = 'lossless';
     5071                    break;
     5072                // Animated/alpha WebP.
     5073                case 'VP8X':
     5074                    // Pad 24-bit int.
     5075                    $width = unpack( 'V', substr( $magic, 24, 3 ) . "\x00" );
     5076                    $width = (int) ( $width[1] & 0xFFFFFF ) + 1;
     5077                    // Pad 24-bit int.
     5078                    $height = unpack( 'V', substr( $magic, 27, 3 ) . "\x00" );
     5079                    $height = (int) ( $height[1] & 0xFFFFFF ) + 1;
     5080                    $type   = 'animated-alpha';
     5081                    break;
     5082            }
     5083        }
     5084    } catch ( Exception $e ) {
     5085    }
     5086    return compact( 'width', 'height', 'type' );
     5087}
     5088
     5089/**
     5090 * Determines if a passed image is a lossy WebP image.
     5091 *
     5092 * @since 5.8.0
     5093 *
     5094 * @param string $filename The file path.
     5095 * @return bool Whether the file is a lossy WebP file.
     5096 */
     5097function _wp_webp_is_lossy( $filename ) {
     5098    $webp_info = wp_get_webp_info( $filename );
     5099    $type      = $webp_info['type'];
     5100    return $type && 'lossy' === $type;
     5101}
     5102
     5103/**
     5104 * Gets the image size, with support for WebP images.
     5105 *
     5106 * @since 5.8.0
     5107 * @access private
     5108 *
     5109 * @param string $filename  The file path.
     5110 * @param array  $imageinfo Extended image information, passed by reference.
     5111 * @return array|false Array of image information or false on failure.
     5112 */
     5113function _wp_get_image_size( $filename, &$imageinfo = array() ) {
     5114    // Try getimagesize() first.
     5115    $info = getimagesize( $filename, $imageinfo );
     5116    if ( false !== $info ) {
     5117        return $info;
     5118    }
     5119    // For PHP versions that don't support WebP images, extract the image
     5120    // size info from the file headers.
     5121    if ( 'image/webp' === wp_get_image_mime( $filename ) ) {
     5122        $webp_info = wp_get_webp_info( $filename );
     5123        $width     = $webp_info['width'];
     5124        $height    = $webp_info['height'];
     5125
     5126            // Mimic the native return format.
     5127        if ( $width && $height ) {
     5128            return array(
     5129                $width,
     5130                $height,
     5131                IMAGETYPE_WEBP, // phpcs:ignore PHPCompatibility.Constants.NewConstants.imagetype_webpFound
     5132                sprintf(
     5133                    'width="%d" height="%d"',
     5134                    $width,
     5135                    $height
     5136                ),
     5137                'mime' => 'image/webp',
     5138            );
     5139        }
     5140    }
     5141
     5142    // The image could not be parsed.
     5143    return false;
     5144}
Note: See TracChangeset for help on using the changeset viewer.