Make WordPress Core


Ignore:
Timestamp:
12/09/2019 12:02:12 PM (7 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.