Make WordPress Core


Ignore:
Timestamp:
05/04/2021 02:43:36 PM (5 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.