WordPress.org

Make WordPress Core

Ticket #33642: 33642.6.patch

File 33642.6.patch, 7.9 KB (added by mikeschroder, 3 years ago)
  • src/wp-includes/class-wp-image-editor-imagick.php

    diff --git src/wp-includes/class-wp-image-editor-imagick.php src/wp-includes/class-wp-image-editor-imagick.php
    index a14fa40..ce011fe 100644
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    6262                        'writeimage',
    6363                        'getimageblob',
    6464                        'getimagegeometry',
     65                        'getimagedepth',
    6566                        'getimageformat',
    6667                        'setimageformat',
    6768                        'setimagecompression',
    6869                        'setimagecompressionquality',
     70                        'setimagedepth',
    6971                        'setimagepage',
     72                        'setimageproperty',
     73                        'setinterlacescheme',
    7074                        'scaleimage',
    7175                        'cropimage',
    7276                        'rotateimage',
    7377                        'flipimage',
    7478                        'flopimage',
     79                        'unsharpmaskimage',
    7580                );
    7681
    7782                // Now, test for deep requirements within Imagick.
    78                 if ( ! defined( 'imagick::COMPRESSION_JPEG' ) )
     83                if ( ! ( defined( 'imagick::COMPRESSION_JPEG' ) && defined( 'imagick::FILTER_TRIANGLE' ) ) )
    7984                        return false;
    8085
    8186                if ( array_diff( $required_methods, get_class_methods( 'Imagick' ) ) )
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    249254                        return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h );
    250255                }
    251256
     257                // Execute the resize
     258                $thumb_result = $this->thumbnail_image( $dst_w, $dst_h );
     259                if ( is_wp_error( $thumb_result ) ) {
     260                        return $thumb_result;
     261                }
     262
     263                return $this->update_size( $dst_w, $dst_h );
     264        }
     265
     266        /**
     267         * Efficiently resize the current image
     268         *
     269         * This is a WordPress specific implementation of Imagick::thumbnailImage(),
     270         * which resizes an image to given dimentions and removes any associated profiles.
     271         *
     272         * @since 4.5.0
     273         *
     274         * @param int    $dst_w       The destination width.
     275         * @param int    $dst_h       The destination height.
     276         * @param string $filter      Optional. The Imagick filter to use when resizing. Default 'triangle'.
     277         * @param bool   $strip_meta  Optional. Strip all profiles, excluding color profiles, from the image. Default true.
     278         * @return bool|WP_Error
     279         */
     280        protected function thumbnail_image( $dst_w, $dst_h, $filter = 'triangle', $strip_meta = true ) {
     281                $allowed_filters = array(
     282                        'point'     => Imagick::FILTER_POINT,
     283                        'box'       => Imagick::FILTER_BOX,
     284                        'triangle'  => Imagick::FILTER_TRIANGLE,
     285                        'hermite'   => Imagick::FILTER_HERMITE,
     286                        'hanning'   => Imagick::FILTER_HANNING,
     287                        'hamming'   => Imagick::FILTER_HAMMING,
     288                        'blackman'  => Imagick::FILTER_BLACKMAN,
     289                        'gaussian'  => Imagick::FILTER_GAUSSIAN,
     290                        'quadratic' => Imagick::FILTER_QUADRATIC,
     291                        'cubic'     => Imagick::FILTER_CUBIC,
     292                        'catrom'    => Imagick::FILTER_CATROM,
     293                        'mitchell'  => Imagick::FILTER_MITCHELL,
     294                        'lanczos'   => Imagick::FILTER_LANCZOS,
     295                        'bessel'    => Imagick::FILTER_BESSEL,
     296                        'sinc'      => Imagick::FILTER_SINC
     297                );
     298
     299                // Set a default filter if an acceptable one wasn’t passed.
     300                $filter = isset( $filter, $allowed_filters[$filter] ) ? $allowed_filters[$filter] : Imagick::FILTER_TRIANGLE;
     301
     302                /**
     303                 * Filter to override stripping metadata from images when they're resized.
     304                 *
     305                 * This filter only applies when resizing using the Imagick editor since GD
     306                 * always strips profiles by default.
     307                 *
     308                 * @since 4.5.0
     309                 *
     310                 * @param bool $strip_meta Whether to strip image metadata during resizing. Default true.
     311                 */
     312                $strip_meta = apply_filters( 'image_strip_meta', $strip_meta );
     313
     314                // Strip image meta.
     315                if ( $strip_meta ) {
     316                        $strip_result = $this->strip_meta();
     317
     318                        if ( is_wp_error( $strip_result ) ) {
     319                                return $strip_result;
     320                        }
     321                }
     322
    252323                try {
     324                        /*
     325                         * To be more efficient, resample large images to 5x the destination size before resizing
     326                         * whenever the output size is less that 1/3 of the original image size (1/3^2 ~= .111),
     327                         * unless we would be resampling to a scale smaller than 128x128.
     328                         */
     329                        $resize_ratio = ( $dst_w / $this->size['width'] ) * ( $dst_h / $this->size['height'] );
     330                        $sample_factor = 5;
     331
     332                        if ( $resize_ratio < .111 && ( $dst_w * $sample_factor > 128 && $dst_h * $sample_factor > 128 ) ) {
     333                                $this->image->sampleImage( $dst_w * $sample_factor, $dst_h * $sample_factor );
     334                        }
     335
     336                        // Resize to the final output size.
     337                        $this->image->setOption( 'filter:support', '2.0' );
     338                        $this->image->resizeImage( $dst_w, $dst_h, $filter, 1 );
     339
     340                        // Set appropriate quality settings after resizing.
     341                        if ( 'image/jpeg' == $this->mime_type ) {
     342                                $this->image->unsharpMaskImage( 0.25, 0.25, 8, 0.065 );
     343                                $this->image->setOption( 'jpeg:fancy-upsampling', 'off' );
     344                        }
     345
     346                        if ( 'image/png' === $this->mime_type ) {
     347                                $this->image->setOption( 'png:compression-filter', '5' );
     348                                $this->image->setOption( 'png:compression-level', '9' );
     349                                $this->image->setOption( 'png:compression-strategy', '1' );
     350                                $this->image->setOption( 'png:exclude-chunk', 'all' );
     351                        }
     352
    253353                        /**
    254                          * @TODO: Thumbnail is more efficient, given a newer version of Imagemagick.
    255                          * $this->image->thumbnailImage( $dst_w, $dst_h );
     354                         * If alpha channel is not defined, set it opaque.
     355                         *
     356                         * Note that Imagick::getImageAlphaChannel() is only available if Imagick
     357                         * has been compiled against ImageMagick version 6.4.0 or newer.
    256358                         */
    257                         $this->image->scaleImage( $dst_w, $dst_h );
     359                        if ( method_exists( $this->image, 'getImageAlphaChannel') && $this->image->getImageAlphaChannel() === Imagick::ALPHACHANNEL_UNDEFINED ) {
     360                                $this->image->setImageAlphaChannel( Imagick::ALPHACHANNEL_OPAQUE );
     361                        }
     362
     363                        // Limit the  bit depth of resized images to 8 bits per channel.
     364                        if ( 8 < $this->image->getImageDepth() ) {
     365                                $this->image->setImageDepth( 8 );
     366                        }
     367
     368                        $this->image->setInterlaceScheme( Imagick::INTERLACE_NO );
     369
    258370                }
    259371                catch ( Exception $e ) {
    260372                        return new WP_Error( 'image_resize_error', $e->getMessage() );
    261373                }
    262 
    263                 return $this->update_size( $dst_w, $dst_h );
    264374        }
    265375
    266376        /**
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    367477                                if ( ! $dst_h )
    368478                                        $dst_h = $src_h;
    369479
    370                                 $this->image->scaleImage( $dst_w, $dst_h );
     480                                $thumb_result = $this->thumbnail_image( $dst_w, $dst_h );
     481                                if ( is_wp_error( $thumb_result ) ) {
     482                                        return $thumb_result;
     483                                }
     484
    371485                                return $this->update_size();
    372486                        }
    373487                }
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    530644
    531645                return true;
    532646        }
     647
     648        /**
     649         * Strip all image meta except color profiles from an image.
     650         *
     651         * @access public
     652         * @since 4.5.0
     653         */
     654        protected function strip_meta() {
     655                try {
     656                        // Strip profiles.
     657                        foreach ( $this->image->getImageProfiles( '*', true ) as $key => $value ) {
     658                                if ( $key != 'icc' && $key != 'icm' ) {
     659                                        $this->image->removeImageProfile( $key );
     660                                }
     661                        }
     662
     663                        // Strip image properties.
     664                        if ( method_exists( $this->image, 'deleteImageProperty' ) ) {
     665                                $this->image->deleteImageProperty( 'comment' );
     666                                $this->image->deleteImageProperty( 'Thumb::URI' );
     667                                $this->image->deleteImageProperty( 'Thumb::MTime' );
     668                                $this->image->deleteImageProperty( 'Thumb::Size' );
     669                                $this->image->deleteImageProperty( 'Thumb::Mimetype' );
     670                                $this->image->deleteImageProperty( 'software' );
     671                                $this->image->deleteImageProperty( 'Thumb::Image::Width' );
     672                                $this->image->deleteImageProperty( 'Thumb::Image::Height' );
     673                                $this->image->deleteImageProperty( 'Thumb::Document::Pages' );
     674                        } else {
     675                                $this->image->setImageProperty( 'comment', '' );
     676                                $this->image->setImageProperty( 'Thumb::URI', '' );
     677                                $this->image->setImageProperty( 'Thumb::MTime', '' );
     678                                $this->image->setImageProperty( 'Thumb::Size', '' );
     679                                $this->image->setImageProperty( 'Thumb::Mimetype', '' );
     680                                $this->image->setImageProperty( 'software', '' );
     681                                $this->image->setImageProperty( 'Thumb::Image::Width', '' );
     682                                $this->image->setImageProperty( 'Thumb::Image::Height', '' );
     683                                $this->image->setImageProperty( 'Thumb::Document::Pages', '' );
     684                        }
     685                } catch ( Excpetion $e ) {
     686                        return new WP_Error( 'image_strip_meta_error', $e->getMessage() );
     687                }
     688
     689                return true;
     690        }
     691
    533692}