Make WordPress Core

Changeset 46834


Ignore:
Timestamp:
12/09/2019 12:02:12 PM (5 years ago)
Author:
SergeyBiryukov
Message:

Upload: Exclude PNG images from scaling after uploading. Fixes a case where resizing a very large PNG may create a scaled image that has smaller dimensions but larger file size than the original.

Props azaozz.
Merges [46809] to the 5.3 branch.
Fixes #48736.

Location:
branches/5.3
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/5.3

  • branches/5.3/src/wp-admin/includes/image.php

    r46680 r46834  
    245245    }
    246246
    247     /**
    248      * Filters the "BIG image" threshold value.
    249      *
    250      * If the original image width or height is above the threshold, it will be scaled down. The threshold is
    251      * used as max width and max height. The scaled down image will be used as the largest available size, including
    252      * the `_wp_attached_file` post meta value.
    253      *
    254      * Returning `false` from the filter callback will disable the scaling.
    255      *
    256      * @since 5.3.0
    257      *
    258      * @param int    $threshold     The threshold value in pixels. Default 2560.
    259      * @param array  $imagesize     Indexed array of the image width and height (in that order).
    260      * @param string $file          Full path to the uploaded image file.
    261      * @param int    $attachment_id Attachment post ID.
    262      */
    263     $threshold = (int) apply_filters( 'big_image_size_threshold', 2560, $imagesize, $file, $attachment_id );
    264 
    265     // If the original image's dimensions are over the threshold, scale the image
    266     // and use it as the "full" size.
    267     if ( $threshold && ( $image_meta['width'] > $threshold || $image_meta['height'] > $threshold ) ) {
    268         $editor = wp_get_image_editor( $file );
    269 
    270         if ( is_wp_error( $editor ) ) {
    271             // This image cannot be edited.
    272             return $image_meta;
    273         }
    274 
    275         // Resize the image
    276         $resized = $editor->resize( $threshold, $threshold );
    277         $rotated = null;
    278 
    279         // If there is EXIF data, rotate according to EXIF Orientation.
    280         if ( ! is_wp_error( $resized ) && is_array( $exif_meta ) ) {
    281             $resized = $editor->maybe_exif_rotate();
    282             $rotated = $resized;
    283         }
    284 
    285         if ( ! is_wp_error( $resized ) ) {
    286             // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
    287             // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
    288             $saved = $editor->save( $editor->generate_filename( 'scaled' ) );
    289 
    290             if ( ! is_wp_error( $saved ) ) {
    291                 $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id );
    292 
    293                 // If the image was rotated update the stored EXIF data.
    294                 if ( true === $rotated && ! empty( $image_meta['image_meta']['orientation'] ) ) {
    295                     $image_meta['image_meta']['orientation'] = 1;
     247    // Do not scale (large) PNG images. May result in sub-sizes that have greater file size than the original. See #48736.
     248    if ( $imagesize['mime'] !== 'image/png' ) {
     249
     250        /**
     251         * Filters the "BIG image" threshold value.
     252         *
     253         * If the original image width or height is above the threshold, it will be scaled down. The threshold is
     254         * used as max width and max height. The scaled down image will be used as the largest available size, including
     255         * the `_wp_attached_file` post meta value.
     256         *
     257         * Returning `false` from the filter callback will disable the scaling.
     258         *
     259         * @since 5.3.0
     260         *
     261         * @param int    $threshold     The threshold value in pixels. Default 2560.
     262         * @param array  $imagesize     {
     263         *     Indexed array of the image width and height in pixels.
     264         *
     265         *     @type int $0 The image width.
     266         *     @type int $1 The image height.
     267         * }
     268         * @param string $file          Full path to the uploaded image file.
     269         * @param int    $attachment_id Attachment post ID.
     270         */
     271        $threshold = (int) apply_filters( 'big_image_size_threshold', 2560, $imagesize, $file, $attachment_id );
     272
     273        // If the original image's dimensions are over the threshold, scale the image
     274        // and use it as the "full" size.
     275        if ( $threshold && ( $image_meta['width'] > $threshold || $image_meta['height'] > $threshold ) ) {
     276            $editor = wp_get_image_editor( $file );
     277
     278            if ( is_wp_error( $editor ) ) {
     279                // This image cannot be edited.
     280                return $image_meta;
     281            }
     282
     283            // Resize the image
     284            $resized = $editor->resize( $threshold, $threshold );
     285            $rotated = null;
     286
     287            // If there is EXIF data, rotate according to EXIF Orientation.
     288            if ( ! is_wp_error( $resized ) && is_array( $exif_meta ) ) {
     289                $resized = $editor->maybe_exif_rotate();
     290                $rotated = $resized;
     291            }
     292
     293            if ( ! is_wp_error( $resized ) ) {
     294                // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
     295                // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
     296                $saved = $editor->save( $editor->generate_filename( 'scaled' ) );
     297
     298                if ( ! is_wp_error( $saved ) ) {
     299                    $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id );
     300
     301                    // If the image was rotated update the stored EXIF data.
     302                    if ( true === $rotated && ! empty( $image_meta['image_meta']['orientation'] ) ) {
     303                        $image_meta['image_meta']['orientation'] = 1;
     304                    }
     305                } else {
     306                    // TODO: log errors.
    296307                }
    297308            } else {
    298309                // TODO: log errors.
    299310            }
    300         } else {
    301             // TODO: log errors.
    302         }
    303     } elseif ( ! empty( $exif_meta['orientation'] ) && (int) $exif_meta['orientation'] !== 1 ) {
    304         // Rotate the whole original image if there is EXIF data and "orientation" is not 1.
    305 
    306         $editor = wp_get_image_editor( $file );
    307 
    308         if ( is_wp_error( $editor ) ) {
    309             // This image cannot be edited.
    310             return $image_meta;
    311         }
    312 
    313         // Rotate the image
    314         $rotated = $editor->maybe_exif_rotate();
    315 
    316         if ( true === $rotated ) {
    317             // Append `-rotated` to the image file name.
    318             $saved = $editor->save( $editor->generate_filename( 'rotated' ) );
    319 
    320             if ( ! is_wp_error( $saved ) ) {
    321                 $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id );
    322 
    323                 // Update the stored EXIF data.
    324                 if ( ! empty( $image_meta['image_meta']['orientation'] ) ) {
    325                     $image_meta['image_meta']['orientation'] = 1;
     311        } elseif ( ! empty( $exif_meta['orientation'] ) && (int) $exif_meta['orientation'] !== 1 ) {
     312            // Rotate the whole original image if there is EXIF data and "orientation" is not 1.
     313
     314            $editor = wp_get_image_editor( $file );
     315
     316            if ( is_wp_error( $editor ) ) {
     317                // This image cannot be edited.
     318                return $image_meta;
     319            }
     320
     321            // Rotate the image
     322            $rotated = $editor->maybe_exif_rotate();
     323
     324            if ( true === $rotated ) {
     325                // Append `-rotated` to the image file name.
     326                $saved = $editor->save( $editor->generate_filename( 'rotated' ) );
     327
     328                if ( ! is_wp_error( $saved ) ) {
     329                    $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id );
     330
     331                    // Update the stored EXIF data.
     332                    if ( ! empty( $image_meta['image_meta']['orientation'] ) ) {
     333                        $image_meta['image_meta']['orientation'] = 1;
     334                    }
     335                } else {
     336                    // TODO: log errors.
    326337                }
    327             } else {
    328                 // TODO: log errors.
    329338            }
    330339        }
     
    542551         * @since 4.7.0
    543552         *
    544          * @param array $fallback_sizes An array of image size names.
    545          * @param array $metadata       Current attachment metadata.
     553         * @param string[] $fallback_sizes An array of image size names.
     554         * @param array    $metadata       Current attachment metadata.
    546555         */
    547556        $fallback_sizes = apply_filters( 'fallback_intermediate_image_sizes', $fallback_sizes, $metadata );
Note: See TracChangeset for help on using the changeset viewer.