WordPress.org

Make WordPress Core

Ticket #33642: 33642.7.patch

File 33642.7.patch, 7.7 KB (added by joemcgill, 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..528115b 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_name Optional. The Imagick filter to use when resizing. Default 'FILTER_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_name = 'FILTER_TRIANGLE', $strip_meta = true ) {
     281                $allowed_filters = array(
     282                        'FILTER_POINT',
     283                        'FILTER_BOX',
     284                        'FILTER_TRIANGLE',
     285                        'FILTER_HERMITE',
     286                        'FILTER_HANNING',
     287                        'FILTER_HAMMING',
     288                        'FILTER_BLACKMAN',
     289                        'FILTER_GAUSSIAN',
     290                        'FILTER_QUADRATIC',
     291                        'FILTER_CUBIC',
     292                        'FILTER_CATROM',
     293                        'FILTER_MITCHELL',
     294                        'FILTER_LANCZOS',
     295                        'FILTER_BESSEL',
     296                        'FILTER_SINC',
     297                );
     298
     299                /**
     300                 * Set the filter value if '$fitler_name' name is in our whitelist and the related
     301                 * Imagick constant is defined or fall back to our default filter.
     302                 */
     303                if ( in_array( $filter_name, $allowed_filters ) && defined( 'Imagick::' . $filter_name ) ) {
     304                        $filter = constant( 'Imagick::' . $filter_name );
     305                } else {
     306                        $filter = Imagick::FILTER_TRIANGLE;
     307                }
     308
     309                /**
     310                 * Filter to override stripping metadata from images when they're resized.
     311                 *
     312                 * This filter only applies when resizing using the Imagick editor since GD
     313                 * always strips profiles by default.
     314                 *
     315                 * @since 4.5.0
     316                 *
     317                 * @param bool $strip_meta Whether to strip image metadata during resizing. Default true.
     318                 */
     319                $strip_meta = apply_filters( 'image_strip_meta', $strip_meta );
     320
     321                // Strip image meta.
     322                if ( $strip_meta ) {
     323                        $strip_result = $this->strip_meta();
     324
     325                        if ( is_wp_error( $strip_result ) ) {
     326                                return $strip_result;
     327                        }
     328                }
     329
    252330                try {
     331                        /*
     332                         * To be more efficient, resample large images to 5x the destination size before resizing
     333                         * whenever the output size is less that 1/3 of the original image size (1/3^2 ~= .111),
     334                         * unless we would be resampling to a scale smaller than 128x128.
     335                         */
     336                        $resize_ratio = ( $dst_w / $this->size['width'] ) * ( $dst_h / $this->size['height'] );
     337                        $sample_factor = 5;
     338
     339                        if ( $resize_ratio < .111 && ( $dst_w * $sample_factor > 128 && $dst_h * $sample_factor > 128 ) ) {
     340                                $this->image->sampleImage( $dst_w * $sample_factor, $dst_h * $sample_factor );
     341                        }
     342
     343                        // Resize to the final output size.
     344                        $this->image->setOption( 'filter:support', '2.0' );
     345                        $this->image->resizeImage( $dst_w, $dst_h, $filter, 1 );
     346
     347                        // Set appropriate quality settings after resizing.
     348                        if ( 'image/jpeg' == $this->mime_type ) {
     349                                $this->image->unsharpMaskImage( 0.25, 0.25, 8, 0.065 );
     350                                $this->image->setOption( 'jpeg:fancy-upsampling', 'off' );
     351                        }
     352
     353                        if ( 'image/png' === $this->mime_type ) {
     354                                $this->image->setOption( 'png:compression-filter', '5' );
     355                                $this->image->setOption( 'png:compression-level', '9' );
     356                                $this->image->setOption( 'png:compression-strategy', '1' );
     357                                $this->image->setOption( 'png:exclude-chunk', 'all' );
     358                        }
     359
    253360                        /**
    254                          * @TODO: Thumbnail is more efficient, given a newer version of Imagemagick.
    255                          * $this->image->thumbnailImage( $dst_w, $dst_h );
     361                         * If alpha channel is not defined, set it opaque.
     362                         *
     363                         * Note that Imagick::getImageAlphaChannel() is only available if Imagick
     364                         * has been compiled against ImageMagick version 6.4.0 or newer.
    256365                         */
    257                         $this->image->scaleImage( $dst_w, $dst_h );
     366                        if ( method_exists( $this->image, 'getImageAlphaChannel') && $this->image->getImageAlphaChannel() === Imagick::ALPHACHANNEL_UNDEFINED ) {
     367                                $this->image->setImageAlphaChannel( Imagick::ALPHACHANNEL_OPAQUE );
     368                        }
     369
     370                        // Limit the  bit depth of resized images to 8 bits per channel.
     371                        if ( 8 < $this->image->getImageDepth() ) {
     372                                $this->image->setImageDepth( 8 );
     373                        }
     374
     375                        $this->image->setInterlaceScheme( Imagick::INTERLACE_NO );
     376
    258377                }
    259378                catch ( Exception $e ) {
    260379                        return new WP_Error( 'image_resize_error', $e->getMessage() );
    261380                }
    262 
    263                 return $this->update_size( $dst_w, $dst_h );
    264381        }
    265382
    266383        /**
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    367484                                if ( ! $dst_h )
    368485                                        $dst_h = $src_h;
    369486
    370                                 $this->image->scaleImage( $dst_w, $dst_h );
     487                                $thumb_result = $this->thumbnail_image( $dst_w, $dst_h );
     488                                if ( is_wp_error( $thumb_result ) ) {
     489                                        return $thumb_result;
     490                                }
     491
    371492                                return $this->update_size();
    372493                        }
    373494                }
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    530651
    531652                return true;
    532653        }
     654
     655        /**
     656         * Strip all image meta except color profiles from an image.
     657         *
     658         * @access public
     659         * @since 4.5.0
     660         */
     661        protected function strip_meta() {
     662                try {
     663                        // Strip profiles.
     664                        foreach ( $this->image->getImageProfiles( '*', true ) as $key => $value ) {
     665                                if ( $key != 'icc' && $key != 'icm' ) {
     666                                        $this->image->removeImageProfile( $key );
     667                                }
     668                        }
     669
     670                        // Strip image properties.
     671                        if ( method_exists( $this->image, 'deleteImageProperty' ) ) {
     672                                $this->image->deleteImageProperty( 'comment' );
     673                                $this->image->deleteImageProperty( 'Thumb::URI' );
     674                                $this->image->deleteImageProperty( 'Thumb::MTime' );
     675                                $this->image->deleteImageProperty( 'Thumb::Size' );
     676                                $this->image->deleteImageProperty( 'Thumb::Mimetype' );
     677                                $this->image->deleteImageProperty( 'software' );
     678                                $this->image->deleteImageProperty( 'Thumb::Image::Width' );
     679                                $this->image->deleteImageProperty( 'Thumb::Image::Height' );
     680                                $this->image->deleteImageProperty( 'Thumb::Document::Pages' );
     681                        } else {
     682                                $this->image->setImageProperty( 'comment', '' );
     683                                $this->image->setImageProperty( 'Thumb::URI', '' );
     684                                $this->image->setImageProperty( 'Thumb::MTime', '' );
     685                                $this->image->setImageProperty( 'Thumb::Size', '' );
     686                                $this->image->setImageProperty( 'Thumb::Mimetype', '' );
     687                                $this->image->setImageProperty( 'software', '' );
     688                                $this->image->setImageProperty( 'Thumb::Image::Width', '' );
     689                                $this->image->setImageProperty( 'Thumb::Image::Height', '' );
     690                                $this->image->setImageProperty( 'Thumb::Document::Pages', '' );
     691                        }
     692                } catch ( Excpetion $e ) {
     693                        return new WP_Error( 'image_strip_meta_error', $e->getMessage() );
     694                }
     695
     696                return true;
     697        }
     698
    533699}