Make WordPress Core

Ticket #40439: 40439.4.diff

File 40439.4.diff, 24.0 KB (added by azaozz, 4 years ago)
  • src/wp-admin/includes/image.php

     
    6767}
    6868
    6969/**
    70  * Generate post thumbnail attachment meta data.
     70 * Compare the existing image sub-sizes (as saved in the attachment meta)
     71 * to the currently defined image sub-sizes, and return the difference.
    7172 *
     73 * Defined sub-sizes that are larger than the image are skipped.
     74 *
     75 * @since 5.3.0
     76 *
     77 * @param int $attachment_id The image attachment post ID.
     78 * @return array An array of the image sub-sizes that are currently defined but don't exist for this image.
     79 */
     80function wp_get_missing_image_subsizes( $attachment_id ) {
     81        if ( ! wp_attachment_is_image( $attachment_id ) ) {
     82                return array();
     83        }
     84
     85        $defined_sizes = wp_get_defined_image_subsizes();
     86        $image_meta    = wp_get_attachment_metadata( $attachment_id );
     87
     88        // Handle meta errors.
     89        if ( empty( $image_meta ) ) {
     90                return $defined_sizes;
     91        }
     92
     93        $full_width     = (int) $image_meta['width'];
     94        $full_height    = (int) $image_meta['height'];
     95        $possible_sizes = array();
     96
     97        // Skip defined sizes that are larger than the uploaded image.
     98        foreach ( $defined_sizes as $size_name => $size_data ) {
     99                if ( $size_data['crop'] ) {
     100                        if (
     101                                // The uploaded image is large enough,
     102                                $full_width >= $size_data['width'] &&
     103                                $full_height >= $size_data['height'] &&
     104                                // and there is something to crop
     105                                ( $full_width > $size_data['width'] || $full_height > $size_data['height'] )
     106                        ) {
     107                                $possible_sizes[ $size_name ] = $size_data;
     108                        }
     109                } elseif ( empty( $size_data['width'] ) ) {
     110                        if ( $full_height > $size_data['height'] ) {
     111                                $possible_sizes[ $size_name ] = $size_data;
     112                        }
     113                } elseif ( empty( $size_data['height'] ) ) {
     114                        if ( $full_width > $size_data['width'] ) {
     115                                $possible_sizes[ $size_name ] = $size_data;
     116                        }
     117                } else {
     118                        // Width and height are treated as max-width and max-height.
     119                        // One must match, the other depends on the image ratio.
     120                        if ( $full_width > $size_data['width'] || $full_height > $size_data['height'] ) {
     121                                $possible_sizes[ $size_name ] = $size_data;
     122                        }
     123                }
     124        }
     125
     126        if ( ! isset( $image_meta['sizes'] ) || ! is_array( $image_meta['sizes'] ) ) {
     127                $image_meta['sizes'] = array();
     128        }
     129
     130        $missing_sizes = array_diff_key( $possible_sizes, $image_meta['sizes'] );
     131
     132        /**
     133         * Filters the array of missing image sub-sizes for an uploaded image.
     134         *
     135         * @since 5.3.0
     136         *
     137         * @param array $missing_sizes Array with the missing image sub-sizes.
     138         * @param array $image_meta    The image meta data.
     139         * @param int   $attachment_id The image attachment post ID.
     140         */
     141        return apply_filters( 'wp_get_missing_image_subsizes', $missing_sizes, $image_meta, $attachment_id );
     142}
     143
     144/**
     145 * If any of the currently defined image sub-sizes are missing,
     146 * create them and update the image meta data.
     147 *
     148 * @since 5.3.0
     149 *
     150 * @param int $attachment_id The image attachment post ID.
     151 * @return array An array with the added sub-sizes.
     152 */
     153function wp_update_image_subsizes( $attachment_id ) {
     154        $missing_sizes = wp_get_missing_image_subsizes( $attachment_id );
     155
     156        if ( empty( $missing_sizes ) ) {
     157                return array();
     158        }
     159
     160        $image_file = get_attached_file( $attachment_id );
     161        $image_meta = wp_get_attachment_metadata( $attachment_id );
     162
     163        // This also updates the image meta.
     164        $new_meta = wp_create_image_subsizes( $image_file, $image_meta, $attachment_id );
     165
     166        return array_diff_key( $new_meta['sizes'], $image_meta['sizes'] );
     167}
     168
     169/**
     170 * Returns a normalized list of all currently defined image sub-sizes.
     171 *
     172 * @since 5.3.0
     173 * @uses wp_get_additional_image_sizes()
     174 *
     175 * @return array Defined image sub-sizes.
     176 */
     177function wp_get_defined_image_subsizes() {
     178        $additional_sizes = wp_get_additional_image_sizes();
     179        $all_sizes        = array();
     180
     181        foreach ( get_intermediate_image_sizes() as $size_name ) {
     182                $size_data = array(
     183                        'width'  => 0,
     184                        'height' => 0,
     185                        'crop'   => false,
     186                );
     187
     188                if ( isset( $additional_sizes[ $size_name ]['width'] ) ) {
     189                        // For sizes added by plugins and themes.
     190                        $size_data['width'] = intval( $additional_sizes[ $size_name ]['width'] );
     191                } else {
     192                        // For default sizes set in options.
     193                        $size_data['width'] = intval( get_option( "{$size_name}_size_w" ) );
     194                }
     195
     196                if ( isset( $additional_sizes[ $size_name ]['height'] ) ) {
     197                        $size_data['height'] = intval( $additional_sizes[ $size_name ]['height'] );
     198                } else {
     199                        $size_data['height'] = intval( get_option( "{$size_name}_size_h" ) );
     200                }
     201
     202                if ( empty( $size_data['width'] ) && empty( $size_data['height'] ) ) {
     203                        // This size isn't set.
     204                        continue;
     205                }
     206
     207                if ( isset( $additional_sizes[ $size_name ]['crop'] ) ) {
     208                        $size_data['crop'] = (bool) $additional_sizes[ $size_name ]['crop'];
     209                } else {
     210                        $size_data['crop'] = (bool) get_option( "{$size_name}_crop" );
     211                }
     212
     213                $all_sizes[ $size_name ] = $size_data;
     214        }
     215
     216        return $all_sizes;
     217}
     218
     219/**
     220 * Create image sub-sizes and add the related data to the image meta `sizes` array.
     221 *
     222 * Saves/updates the image meta after each sub-size is created.
     223 *
     224 * @since 5.3.0
     225 *
     226 * @param string $file          Full path to the image file.
     227 * @param array  $image_meta    The attachment meta data.
     228 * @param int    $attachment_id Attachment Id to process.
     229 * @return array The attachment meta data with updated `sizes` array.
     230 */
     231function wp_create_image_subsizes( $file, $image_meta, $attachment_id ) {
     232        $new_sizes = wp_get_defined_image_subsizes();
     233        /**
     234         * Filters the image sizes automatically generated when uploading an image.
     235         *
     236         * @since 2.9.0
     237         * @since 4.4.0 Added the `$metadata` argument.
     238         * @since 5.3.0 Added the `$attachment_id` argument.
     239         *
     240         * @param array $sizes         An associative array of image sizes.
     241         * @param array $metadata      An associative array of image metadata: width, height, file.
     242         * @param int   $attachment_id The attachment post ID for the image.
     243         */
     244        $new_sizes = apply_filters( 'intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id );
     245
     246        // Check if any sizes already exist.
     247        // Only checks "size names" so we don't override existing images even if the dimensions don't match
     248        // the currently defined size with the same name.
     249        if ( isset( $image_meta['sizes'] ) && is_array( $image_meta['sizes'] ) ) {
     250                foreach ( $image_meta['sizes'] as $size_name => $current_meta ) {
     251                        if ( array_key_exists( $size_name, $new_sizes ) ) {
     252                                unset( $new_sizes[ $size_name ] );
     253                        }
     254                }
     255        } else {
     256                $image_meta['sizes'] = array();
     257        }
     258
     259        if ( ! empty( $new_sizes ) ) {
     260                $editor = wp_get_image_editor( $file );
     261
     262                if ( ! is_wp_error( $editor ) ) {
     263                        if ( method_exists( $editor, 'make_subsize' ) ) {
     264                                foreach ( $new_sizes as $new_size_name => $new_size_data ) {
     265                                        $size_meta = $editor->make_subsize( $new_size_data );
     266
     267                                        if ( ! is_wp_error( $size_meta ) ) {
     268                                                // The sub-size was created successfully. Save the size meta value.
     269                                                $image_meta['sizes'][ $new_size_name ] = $size_meta;
     270                                                wp_update_attachment_metadata( $attachment_id, $image_meta );
     271                                        } else {
     272                                                // TO-DO: This happens in the background. Add proper/better error messages handling.
     273                                        }
     274                                }
     275                        } else {
     276                                // Fall back to `$editor->multi_resize()`.
     277                                $created_sizes = $editor->multi_resize( $new_sizes );
     278
     279                                if ( ! empty( $created_sizes ) ) {
     280                                        $image_meta['sizes'] = array_merge( $image_meta['sizes'], $created_sizes );
     281                                        wp_update_attachment_metadata( $attachment_id, $image_meta );
     282                                }
     283                        }
     284                }
     285        }
     286
     287        return $image_meta;
     288}
     289
     290/**
     291 * Generate attachment meta data and create image sub-sizes for images.
     292 *
    72293 * @since 2.1.0
    73294 *
    74295 * @param int $attachment_id Attachment Id to process.
     
    90311                // Make the file path relative to the upload dir.
    91312                $metadata['file'] = _wp_relative_upload_path( $file );
    92313
    93                 // Make thumbnails and other intermediate sizes.
    94                 $_wp_additional_image_sizes = wp_get_additional_image_sizes();
    95 
    96                 $sizes = array();
    97                 foreach ( get_intermediate_image_sizes() as $s ) {
    98                         $sizes[ $s ] = array(
    99                                 'width'  => '',
    100                                 'height' => '',
    101                                 'crop'   => false,
    102                         );
    103                         if ( isset( $_wp_additional_image_sizes[ $s ]['width'] ) ) {
    104                                 // For theme-added sizes
    105                                 $sizes[ $s ]['width'] = intval( $_wp_additional_image_sizes[ $s ]['width'] );
    106                         } else {
    107                                 // For default sizes set in options
    108                                 $sizes[ $s ]['width'] = get_option( "{$s}_size_w" );
    109                         }
    110 
    111                         if ( isset( $_wp_additional_image_sizes[ $s ]['height'] ) ) {
    112                                 // For theme-added sizes
    113                                 $sizes[ $s ]['height'] = intval( $_wp_additional_image_sizes[ $s ]['height'] );
    114                         } else {
    115                                 // For default sizes set in options
    116                                 $sizes[ $s ]['height'] = get_option( "{$s}_size_h" );
    117                         }
    118 
    119                         if ( isset( $_wp_additional_image_sizes[ $s ]['crop'] ) ) {
    120                                 // For theme-added sizes
    121                                 $sizes[ $s ]['crop'] = $_wp_additional_image_sizes[ $s ]['crop'];
    122                         } else {
    123                                 // For default sizes set in options
    124                                 $sizes[ $s ]['crop'] = get_option( "{$s}_crop" );
    125                         }
    126                 }
    127 
    128                 /**
    129                  * Filters the image sizes automatically generated when uploading an image.
    130                  *
    131                  * @since 2.9.0
    132                  * @since 4.4.0 Added the `$metadata` argument.
    133                  * @since 5.1.0 Added the `$attachment_id` argument.
    134                  *
    135                  * @param array $sizes         An associative array of image sizes.
    136                  * @param array $metadata      An associative array of image metadata: width, height, file.
    137                  * @param int   $attachment_id Current attachment ID.
    138                  */
    139                 $sizes = apply_filters( 'intermediate_image_sizes_advanced', $sizes, $metadata, $attachment_id );
    140 
    141                 if ( $sizes ) {
    142                         $editor = wp_get_image_editor( $file );
    143 
    144                         if ( ! is_wp_error( $editor ) ) {
    145                                 $metadata['sizes'] = $editor->multi_resize( $sizes );
    146                         }
    147                 } else {
    148                         $metadata['sizes'] = array();
    149                 }
    150 
    151314                // Fetch additional metadata from EXIF/IPTC.
    152315                $image_meta = wp_read_image_metadata( $file );
    153316                if ( $image_meta ) {
    154317                        $metadata['image_meta'] = $image_meta;
    155318                }
     319
     320                // Make thumbnails and other intermediate sizes.
     321                $metadata = wp_create_image_subsizes( $file, $metadata, $attachment_id );
    156322        } elseif ( wp_attachment_is( 'video', $attachment ) ) {
    157323                $metadata = wp_read_video_metadata( $file );
    158324                $support  = current_theme_supports( 'post-thumbnails', 'attachment:video' ) || post_type_supports( 'attachment:video', 'thumbnail' );
     
    234400                 */
    235401                $fallback_sizes = apply_filters( 'fallback_intermediate_image_sizes', $fallback_sizes, $metadata );
    236402
    237                 $sizes                      = array();
    238                 $_wp_additional_image_sizes = wp_get_additional_image_sizes();
     403                $defined_sizes = wp_get_defined_image_subsizes();
     404                $merged_sizes  = array_intersect_key( $defined_sizes, array_flip( $fallback_sizes ) );
    239405
    240                 foreach ( $fallback_sizes as $s ) {
    241                         if ( isset( $_wp_additional_image_sizes[ $s ]['width'] ) ) {
    242                                 $sizes[ $s ]['width'] = intval( $_wp_additional_image_sizes[ $s ]['width'] );
    243                         } else {
    244                                 $sizes[ $s ]['width'] = get_option( "{$s}_size_w" );
    245                         }
    246 
    247                         if ( isset( $_wp_additional_image_sizes[ $s ]['height'] ) ) {
    248                                 $sizes[ $s ]['height'] = intval( $_wp_additional_image_sizes[ $s ]['height'] );
    249                         } else {
    250                                 $sizes[ $s ]['height'] = get_option( "{$s}_size_h" );
    251                         }
    252 
    253                         if ( isset( $_wp_additional_image_sizes[ $s ]['crop'] ) ) {
    254                                 $sizes[ $s ]['crop'] = $_wp_additional_image_sizes[ $s ]['crop'];
    255                         } else {
    256                                 // Force thumbnails to be soft crops.
    257                                 if ( 'thumbnail' !== $s ) {
    258                                         $sizes[ $s ]['crop'] = get_option( "{$s}_crop" );
    259                                 }
    260                         }
     406                // Force thumbnails to be soft crops.
     407                if ( isset( $merged_sizes['thumbnail'] ) && is_array( $merged_sizes['thumbnail'] ) ) {
     408                        $merged_sizes['thumbnail']['crop'] = false;
    261409                }
    262410
    263411                // Only load PDFs in an image editor if we're processing sizes.
    264                 if ( ! empty( $sizes ) ) {
     412                if ( ! empty( $merged_sizes ) ) {
    265413                        $editor = wp_get_image_editor( $file );
    266414
    267415                        if ( ! is_wp_error( $editor ) ) { // No support for this type of file
     
    282430                                        unset( $uploaded['path'] );
    283431
    284432                                        if ( ! is_wp_error( $editor ) ) {
    285                                                 $metadata['sizes']         = $editor->multi_resize( $sizes );
     433                                                $metadata['sizes']         = $editor->multi_resize( $merged_sizes );
    286434                                                $metadata['sizes']['full'] = $uploaded;
    287435                                        }
    288436                                }
     
    654802        $filepath = get_attached_file( $attachment_id );
    655803
    656804        if ( $filepath && file_exists( $filepath ) ) {
    657                 if ( 'full' != $size && ( $data = image_get_intermediate_size( $attachment_id, $size ) ) ) {
     805                $data = image_get_intermediate_size( $attachment_id, $size );
     806
     807                if ( 'full' != $size && $data ) {
     808                        $filepath = path_join( dirname( $filepath ), $data['file'] );
     809
    658810                        /**
    659811                         * Filters the path to the current image.
    660812                         *
     
    666818                         * @param string $attachment_id Attachment ID.
    667819                         * @param string $size          Size of the image.
    668820                         */
    669                         $filepath = apply_filters( 'load_image_to_edit_filesystempath', path_join( dirname( $filepath ), $data['file'] ), $attachment_id, $size );
     821                        $filepath = apply_filters( 'load_image_to_edit_filesystempath', $filepath, $attachment_id, $size );
    670822                }
    671         } elseif ( function_exists( 'fopen' ) && true == ini_get( 'allow_url_fopen' ) ) {
     823        } elseif ( function_exists( 'fopen' ) && true === ini_get( 'allow_url_fopen' ) ) {
    672824                /**
    673825                 * Filters the image URL if not in the local filesystem.
    674826                 *
     
    705857 * @return string|false New file path on success, false on failure.
    706858 */
    707859function _copy_image_file( $attachment_id ) {
    708         $dst_file = $src_file = get_attached_file( $attachment_id );
     860        $dst_file = get_attached_file( $attachment_id );
     861        $src_file = $dst_file;
     862
    709863        if ( ! file_exists( $src_file ) ) {
    710864                $src_file = _load_image_to_edit_path( $attachment_id );
    711865        }
  • src/wp-includes/class-wp-image-editor-gd.php

     
    4343
    4444                // On some setups GD library does not provide imagerotate() - Ticket #11536
    4545                if ( isset( $args['methods'] ) &&
    46                         in_array( 'rotate', $args['methods'] ) &&
     46                        in_array( 'rotate', $args['methods'], true ) &&
    4747                        ! function_exists( 'imagerotate' ) ) {
    4848
    4949                                return false;
     
    217217         * @return array An array of resized images' metadata by size.
    218218         */
    219219        public function multi_resize( $sizes ) {
    220                 $metadata  = array();
    221                 $orig_size = $this->size;
     220                $metadata = array();
    222221
    223222                foreach ( $sizes as $size => $size_data ) {
    224                         if ( ! isset( $size_data['width'] ) && ! isset( $size_data['height'] ) ) {
    225                                 continue;
    226                         }
     223                        $meta = $this->make_subsize( $size_data );
    227224
    228                         if ( ! isset( $size_data['width'] ) ) {
    229                                 $size_data['width'] = null;
     225                        if ( ! is_wp_error( $meta ) ) {
     226                                $metadata[ $size ] = $meta;
    230227                        }
    231                         if ( ! isset( $size_data['height'] ) ) {
    232                                 $size_data['height'] = null;
    233                         }
     228                }
    234229
    235                         if ( ! isset( $size_data['crop'] ) ) {
    236                                 $size_data['crop'] = false;
    237                         }
     230                return $metadata;
     231        }
    238232
    239                         $image     = $this->_resize( $size_data['width'], $size_data['height'], $size_data['crop'] );
    240                         $duplicate = ( ( $orig_size['width'] == $size_data['width'] ) && ( $orig_size['height'] == $size_data['height'] ) );
     233        /**
     234         * Create an image sub-size and return the image meta data value for it.
     235         *
     236         * @since 5.3.0
     237         *
     238         * @param array $size_data Array of height, width and whether to crop.
     239         * @return WP_Error|array WP_Error on error, or the image data array for inclusion in the `sizes` array in the image meta.
     240         */
     241        public function make_subsize( $size_data ) {
     242                if ( ! isset( $size_data['width'] ) && ! isset( $size_data['height'] ) ) {
     243                        return new WP_Error( 'image_subsize_create_error', __( 'Cannot resize the image. Both width and height are not set.' ) );
     244                }
    241245
    242                         if ( ! is_wp_error( $image ) && ! $duplicate ) {
    243                                 $resized = $this->_save( $image );
     246                $orig_size = $this->size;
    244247
    245                                 imagedestroy( $image );
     248                if ( ! isset( $size_data['width'] ) ) {
     249                        $size_data['width'] = null;
     250                }
    246251
    247                                 if ( ! is_wp_error( $resized ) && $resized ) {
    248                                         unset( $resized['path'] );
    249                                         $metadata[ $size ] = $resized;
    250                                 }
    251                         }
     252                if ( ! isset( $size_data['height'] ) ) {
     253                        $size_data['height'] = null;
     254                }
    252255
     256                if ( ! isset( $size_data['crop'] ) ) {
     257                        $size_data['crop'] = false;
     258                }
     259
     260                $resized   = $this->_resize( $size_data['width'], $size_data['height'], $size_data['crop'] );
     261                $duplicate = ( intval( $orig_size['width'] ) === intval( $this->size['width'] ) && intval( $orig_size['height'] ) === intval( $this->size['height'] ) );
     262
     263                if ( is_wp_error( $resized ) ) {
    253264                        $this->size = $orig_size;
     265                        return $resized;
    254266                }
    255267
    256                 return $metadata;
     268                if ( ! $duplicate ) {
     269                        $saved = $this->_save( $resized );
     270
     271                        if ( ! is_wp_error( $saved ) ) {
     272                                unset( $saved['path'] );
     273                        }
     274                } else {
     275                        $saved = new WP_Error( 'image_create_identical_subsize' );
     276                }
     277
     278                imagedestroy( $resized );
     279                $this->size = $orig_size;
     280
     281                return $saved;
    257282        }
    258283
    259284        /**
     
    391416                        $filename = $this->generate_filename( null, null, $extension );
    392417                }
    393418
    394                 if ( 'image/gif' == $mime_type ) {
     419                if ( 'image/gif' === $mime_type ) {
    395420                        if ( ! $this->make_image( $filename, 'imagegif', array( $image, $filename ) ) ) {
    396421                                return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
    397422                        }
    398                 } elseif ( 'image/png' == $mime_type ) {
     423                } elseif ( 'image/png' === $mime_type ) {
    399424                        // convert from full colors to index colors, like original PNG.
    400425                        if ( function_exists( 'imageistruecolor' ) && ! imageistruecolor( $image ) ) {
    401426                                imagetruecolortopalette( $image, false, imagecolorstotal( $image ) );
     
    404429                        if ( ! $this->make_image( $filename, 'imagepng', array( $image, $filename ) ) ) {
    405430                                return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
    406431                        }
    407                 } elseif ( 'image/jpeg' == $mime_type ) {
     432                } elseif ( 'image/jpeg' === $mime_type ) {
    408433                        if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, $this->get_quality() ) ) ) {
    409434                                return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
    410435                        }
  • src/wp-includes/class-wp-image-editor-imagick.php

     
    108108
    109109                // setIteratorIndex is optional unless mime is an animated format.
    110110                // Here, we just say no if you are missing it and aren't loading a jpeg.
    111                 if ( ! method_exists( 'Imagick', 'setIteratorIndex' ) && $mime_type != 'image/jpeg' ) {
     111                if ( ! method_exists( 'Imagick', 'setIteratorIndex' ) && $mime_type !== 'image/jpeg' ) {
    112112                                return false;
    113113                }
    114114
     
    146146                        $file_extension = strtolower( pathinfo( $this->file, PATHINFO_EXTENSION ) );
    147147                        $filename       = $this->file;
    148148
    149                         if ( 'pdf' == $file_extension ) {
     149                        if ( 'pdf' === $file_extension ) {
    150150                                $filename = $this->pdf_setup();
    151151                        }
    152152
     
    193193                }
    194194
    195195                try {
    196                         if ( 'image/jpeg' == $this->mime_type ) {
     196                        if ( 'image/jpeg' === $this->mime_type ) {
    197197                                $this->image->setImageCompressionQuality( $quality );
    198198                                $this->image->setImageCompression( imagick::COMPRESSION_JPEG );
    199199                        } else {
     
    260260                if ( ! $dims ) {
    261261                        return new WP_Error( 'error_getting_dimensions', __( 'Could not calculate resized image dimensions' ) );
    262262                }
     263
    263264                list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
    264265
    265266                if ( $crop ) {
     
    312313                 * Set the filter value if '$filter_name' name is in our whitelist and the related
    313314                 * Imagick constant is defined or fall back to our default filter.
    314315                 */
    315                 if ( in_array( $filter_name, $allowed_filters ) && defined( 'Imagick::' . $filter_name ) ) {
     316                if ( in_array( $filter_name, $allowed_filters, true ) && defined( 'Imagick::' . $filter_name ) ) {
    316317                        $filter = constant( 'Imagick::' . $filter_name );
    317318                } else {
    318319                        $filter = defined( 'Imagick::FILTER_TRIANGLE' ) ? Imagick::FILTER_TRIANGLE : false;
     
    361362                        }
    362363
    363364                        // Set appropriate quality settings after resizing.
    364                         if ( 'image/jpeg' == $this->mime_type ) {
     365                        if ( 'image/jpeg' === $this->mime_type ) {
    365366                                if ( is_callable( array( $this->image, 'unsharpMaskImage' ) ) ) {
    366367                                        $this->image->unsharpMaskImage( 0.25, 0.25, 8, 0.065 );
    367368                                }
     
    413414         * @since 3.5.0
    414415         *
    415416         * @param array $sizes {
    416          *     An array of image size arrays. Default sizes are 'small', 'medium', 'medium_large', 'large'.
     417         *     An array of image size arrays. Default sizes are 'thumbnail', 'medium', 'medium_large', 'large'.
    417418         *
    418419         *     Either a height or width must be provided.
    419420         *     If one of the two is set to null, the resize will
     
    430431         * @return array An array of resized images' metadata by size.
    431432         */
    432433        public function multi_resize( $sizes ) {
    433                 $metadata   = array();
    434                 $orig_size  = $this->size;
    435                 $orig_image = $this->image->getImage();
     434                $metadata = array();
    436435
    437436                foreach ( $sizes as $size => $size_data ) {
    438                         if ( ! $this->image ) {
    439                                 $this->image = $orig_image->getImage();
    440                         }
     437                        $meta = $this->make_subsize( $size_data );
    441438
    442                         if ( ! isset( $size_data['width'] ) && ! isset( $size_data['height'] ) ) {
    443                                 continue;
     439                        if ( ! is_wp_error( $meta ) ) {
     440                                $metadata[ $size ] = $meta;
    444441                        }
     442                }
    445443
    446                         if ( ! isset( $size_data['width'] ) ) {
    447                                 $size_data['width'] = null;
    448                         }
    449                         if ( ! isset( $size_data['height'] ) ) {
    450                                 $size_data['height'] = null;
    451                         }
     444                return $metadata;
     445        }
    452446
    453                         if ( ! isset( $size_data['crop'] ) ) {
    454                                 $size_data['crop'] = false;
    455                         }
     447        /**
     448         * Create an image sub-size and return the image meta data value for it.
     449         *
     450         * @since 5.3.0
     451         *
     452         * @param array $size_data Array of height, width and whether to crop.
     453         * @return WP_Error|array WP_Error on error, or the image data array for inclusion in the `sizes` array in the image meta.
     454         */
     455        public function make_subsize( $size_data ) {
     456                if ( ! isset( $size_data['width'] ) && ! isset( $size_data['height'] ) ) {
     457                        return new WP_Error( 'image_subsize_create_error', __( 'Cannot resize the image. Both width and height are not set.' ) );
     458                }
    456459
    457                         $resize_result = $this->resize( $size_data['width'], $size_data['height'], $size_data['crop'] );
    458                         $duplicate     = ( ( $orig_size['width'] == $size_data['width'] ) && ( $orig_size['height'] == $size_data['height'] ) );
     460                $orig_size  = $this->size;
     461                $orig_image = $this->image->getImage();
    459462
    460                         if ( ! is_wp_error( $resize_result ) && ! $duplicate ) {
    461                                 $resized = $this->_save( $this->image );
     463                if ( ! isset( $size_data['width'] ) ) {
     464                        $size_data['width'] = null;
     465                }
    462466
    463                                 $this->image->clear();
    464                                 $this->image->destroy();
    465                                 $this->image = null;
     467                if ( ! isset( $size_data['height'] ) ) {
     468                        $size_data['height'] = null;
     469                }
    466470
    467                                 if ( ! is_wp_error( $resized ) && $resized ) {
    468                                         unset( $resized['path'] );
    469                                         $metadata[ $size ] = $resized;
    470                                 }
    471                         }
     471                if ( ! isset( $size_data['crop'] ) ) {
     472                        $size_data['crop'] = false;
     473                }
    472474
    473                         $this->size = $orig_size;
     475                $resized   = $this->resize( $size_data['width'], $size_data['height'], $size_data['crop'] );
     476                $duplicate = ( intval( $orig_size['width'] ) === intval( $this->size['width'] ) && intval( $orig_size['height'] ) === intval( $this->size['height'] ) );
     477
     478                if ( is_wp_error( $resized ) ) {
     479                        $this->size  = $orig_size;
     480                        $this->image = $orig_image->getImage();
     481                        return $resized;
    474482                }
    475483
    476                 $this->image = $orig_image;
     484                if ( ! $duplicate ) {
     485                        $saved = $this->_save( $this->image );
    477486
    478                 return $metadata;
     487                        if ( ! is_wp_error( $saved ) ) {
     488                                unset( $saved['path'] );
     489                        }
     490                } else {
     491                        $saved = new WP_Error( 'image_create_identical_subsize' );
     492                }
     493
     494                $this->image->clear();
     495                $this->image->destroy();
     496                $this->image = null;
     497                $this->size  = $orig_size;
     498                $this->image = $orig_image->getImage();
     499
     500                return $saved;
    479501        }
    480502
    481503        /**
     
    717739                try {
    718740                        // Strip profiles.
    719741                        foreach ( $this->image->getImageProfiles( '*', true ) as $key => $value ) {
    720                                 if ( ! in_array( $key, $protected_profiles ) ) {
     742                                if ( ! in_array( $key, $protected_profiles, true ) ) {
    721743                                        $this->image->removeImageProfile( $key );
    722744                                }
    723745                        }