WordPress.org

Make WordPress Core

Ticket #33642: 33642.5.patch

File 33642.5.patch, 7.4 KB (added by joemcgill, 4 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..de0bc82 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.
    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                $this->thumbnail_image( $dst_w, $dst_h );
     259
     260                return $this->update_size( $dst_w, $dst_h );
     261        }
     262
     263        /**
     264         * Efficiently resize the current image
     265         *
     266         * This is a WordPress specific implementation of Imagick::thumbnailImage(),
     267         * which resizes an image to given dimentions and removes any associated profiles.
     268         *
     269         * @since 4.5.0
     270         *
     271         * @param int    $dst_w       The destination width.
     272         * @param int    $dst_h       The destination height.
     273         * @param string $filter      Optional. The Imagick filter to use when resizing. Default 'triangle'.
     274         * @param bool   $strip_meta  Optional. Strip all profiles, exluding color profiles, from the image. Default true.
     275         * @return bool|WP_Error
     276         */
     277        protected function thumbnail_image( $dst_w, $dst_h, $filter = 'triangle', $strip_meta = true ) {
     278                $allowed_filters = array(
     279                        'point'     => Imagick::FILTER_POINT,
     280                        'box'       => Imagick::FILTER_BOX,
     281                        'triangle'  => Imagick::FILTER_TRIANGLE,
     282                        'hermite'   => Imagick::FILTER_HERMITE,
     283                        'hanning'   => Imagick::FILTER_HANNING,
     284                        'hamming'   => Imagick::FILTER_HAMMING,
     285                        'blackman'  => Imagick::FILTER_BLACKMAN,
     286                        'gaussian'  => Imagick::FILTER_GAUSSIAN,
     287                        'quadratic' => Imagick::FILTER_QUADRATIC,
     288                        'cubic'     => Imagick::FILTER_CUBIC,
     289                        'catrom'    => Imagick::FILTER_CATROM,
     290                        'mitchell'  => Imagick::FILTER_MITCHELL,
     291                        'lanczos'   => Imagick::FILTER_LANCZOS,
     292                        'bessel'    => Imagick::FILTER_BESSEL,
     293                        'sinc'      => Imagick::FILTER_SINC
     294                );
     295
     296                // Set a default filter if an acceptable one wasn’t passed.
     297                $filter = isset( $filter, $allowed_filters ) ? $allowed_filters[$filter] : Imagick::FILTER_TRIANGLE;
     298
    252299                try {
     300
    253301                        /**
    254                          * @TODO: Thumbnail is more efficient, given a newer version of Imagemagick.
    255                          * $this->image->thumbnailImage( $dst_w, $dst_h );
     302                         * Filter to override stripping metadata from images when they're resized.
     303                         *
     304                         * This filter only applies when resizing using the Imagick editor since GD
     305                         * always strips profiles by default.
     306                         *
     307                         * @since 4.5.0
     308                         *
     309                         * @param bool $strip_meta Whether to strip image metadata during resizing. Default true.
    256310                         */
    257                         $this->image->scaleImage( $dst_w, $dst_h );
     311                        $strip_meta = apply_filters( 'image_strip_meta', $strip_meta );
     312
     313                        // Strip image meta.
     314                        if ( $strip_meta ) {
     315                                $this->strip_meta();
     316                        }
     317
     318                        /*
     319                         * To be more efficient, resample large images to 5x the destination size before resizing
     320                         * whenever the output size is less that 1/3 of the original image size (1/3^2 ~= .111),
     321                         * unless we would be resampling to a scale smaller than 128x128.
     322                         */
     323                        $resize_ratio = ( $dst_w / $this->size['width'] ) * ( $dst_h / $this->size['height'] );
     324                        $sample_factor = 5;
     325
     326                        if ( $resize_ratio < .111 && ( $dst_w * $sample_factor > 128 && $dst_h * $sample_factor > 128 ) ) {
     327                                $this->image->sampleImage( $dst_w * $sample_factor, $dst_h * $sample_factor );
     328                        }
     329
     330                        // Resize to the final output size.
     331                        $this->image->setOption( 'filter:support', '2.0' );
     332                        $this->image->resizeImage( $dst_w, $dst_h, $filter, 1 );
     333
     334                        // Set appropriate quality settings after resizing.
     335                        if ( 'image/jpeg' == $this->mime_type ) {
     336                                $this->image->unsharpMaskImage( 0.25, 0.25, 8, 0.065 );
     337                                $this->image->setOption( 'jpeg:fancy-upsampling', 'off' );
     338                        }
     339
     340                        if ( 'image/png' === $this->mime_type ) {
     341                                $this->image->setOption( 'png:compression-filter', '5' );
     342                                $this->image->setOption( 'png:compression-level', '9' );
     343                                $this->image->setOption( 'png:compression-strategy', '1' );
     344                                $this->image->setOption( 'png:exclude-chunk', 'all' );
     345                        }
     346
     347                        /**
     348                         * If alpha channel is not defined, set it opaque.
     349                         *
     350                         * Note that Imagick::getImageAlphaChannel() is only available if Imagick
     351                         * has been compiled against ImageMagick version 6.4.0 or newer.
     352                         */
     353                        if ( method_exists( $this->image, 'getImageAlphaChannel') && $this->image->getImageAlphaChannel() === Imagick::ALPHACHANNEL_UNDEFINED ) {
     354                                $this->image->setImageAlphaChannel( Imagick::ALPHACHANNEL_OPAQUE );
     355                        }
     356
     357                        // Limit the  bit depth of resized images to 8 bits per channel.
     358                        if ( 8 < $this->image->getImageDepth() ) {
     359                                $this->image->setImageDepth( 8 );
     360                        }
     361
     362                        $this->image->setInterlaceScheme( Imagick::INTERLACE_NO );
     363
    258364                }
    259365                catch ( Exception $e ) {
    260366                        return new WP_Error( 'image_resize_error', $e->getMessage() );
    261367                }
    262 
    263                 return $this->update_size( $dst_w, $dst_h );
    264368        }
    265369
    266370        /**
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    367471                                if ( ! $dst_h )
    368472                                        $dst_h = $src_h;
    369473
    370                                 $this->image->scaleImage( $dst_w, $dst_h );
     474                                $this->thumbnail_image( $dst_w, $dst_h );
    371475                                return $this->update_size();
    372476                        }
    373477                }
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    530634
    531635                return true;
    532636        }
     637
     638        /**
     639         * Strip all image meta except color profiles from an image.
     640         *
     641         * @access public
     642         * @since 4.5.0
     643         */
     644        protected function strip_meta() {
     645                try {
     646                        // Strip profiles.
     647                        foreach ( $this->image->getImageProfiles( '*', true ) as $key => $value ) {
     648                                if ( $key != 'icc' && $key != 'icm' ) {
     649                                        $this->image->removeImageProfile( $key );
     650                                }
     651                        }
     652
     653                        // Strip image properties.
     654                        if ( method_exists( $this->image, 'deleteImageProperty' ) ) {
     655                                $this->image->deleteImageProperty( 'comment' );
     656                                $this->image->deleteImageProperty( 'Thumb::URI' );
     657                                $this->image->deleteImageProperty( 'Thumb::MTime' );
     658                                $this->image->deleteImageProperty( 'Thumb::Size' );
     659                                $this->image->deleteImageProperty( 'Thumb::Mimetype' );
     660                                $this->image->deleteImageProperty( 'software' );
     661                                $this->image->deleteImageProperty( 'Thumb::Image::Width' );
     662                                $this->image->deleteImageProperty( 'Thumb::Image::Height' );
     663                                $this->image->deleteImageProperty( 'Thumb::Document::Pages' );
     664                        } else {
     665                                $this->image->setImageProperty( 'comment', '' );
     666                                $this->image->setImageProperty( 'Thumb::URI', '' );
     667                                $this->image->setImageProperty( 'Thumb::MTime', '' );
     668                                $this->image->setImageProperty( 'Thumb::Size', '' );
     669                                $this->image->setImageProperty( 'Thumb::Mimetype', '' );
     670                                $this->image->setImageProperty( 'software', '' );
     671                                $this->image->setImageProperty( 'Thumb::Image::Width', '' );
     672                                $this->image->setImageProperty( 'Thumb::Image::Height', '' );
     673                                $this->image->setImageProperty( 'Thumb::Document::Pages', '' );
     674                        }
     675                } catch ( Excpetion $e ) {
     676                        return new WP_Error( 'image_strip_meta_error', $e->getMessage() );
     677                }
     678
     679                return true;
     680        }
     681
    533682}