Make WordPress Core

Changeset 36891


Ignore:
Timestamp:
03/09/2016 04:43:40 AM (9 years ago)
Author:
mikeschroder
Message:

Media: Progressive enhancement for Imagick; add profiles to whitelist.

  • Progressive enhancement for optional compression improvements and stripping meta.
  • Whitelist IPTC and XMP profiles to maintain Copyright and Rights Usage Terms.
  • Whitelist EXIF profile to maintain orientation information. If handled on upload in the future, it can be stripped as well.

Fixes #33642. See #28634.
Props joemcgill, juliobox, ahockley, markoheijnen, adamsilverstein, wonderboymusic, mikeschroder.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-image-editor-imagick.php

    r36847 r36891  
    6363            'getimageblob',
    6464            'getimagegeometry',
    65             'getimagedepth',
    6665            'getimageformat',
    6766            'setimageformat',
    6867            'setimagecompression',
    6968            'setimagecompressionquality',
    70             'setimagedepth',
    7169            'setimagepage',
    72             'setimageproperty',
    73             'setinterlacescheme',
     70            'setoption',
    7471            'scaleimage',
    7572            'cropimage',
     
    7774            'flipimage',
    7875            'flopimage',
    79             'unsharpmaskimage',
    8076        );
    8177
    8278        // Now, test for deep requirements within Imagick.
    83         if ( ! ( defined( 'imagick::COMPRESSION_JPEG' ) && defined( 'imagick::FILTER_TRIANGLE' ) ) )
     79        if ( ! defined( 'imagick::COMPRESSION_JPEG' ) )
    8480            return false;
    8581
     
    305301            $filter = constant( 'Imagick::' . $filter_name );
    306302        } else {
    307             $filter = Imagick::FILTER_TRIANGLE;
     303            $filter = defined( 'Imagick::FILTER_TRIANGLE' ) ? Imagick::FILTER_TRIANGLE : false;
    308304        }
    309305
     
    318314         * @param bool $strip_meta Whether to strip image metadata during resizing. Default true.
    319315         */
    320         $strip_meta = apply_filters( 'image_strip_meta', $strip_meta );
    321 
    322         // Strip image meta.
    323         if ( $strip_meta ) {
    324             $strip_result = $this->strip_meta();
    325 
    326             if ( is_wp_error( $strip_result ) ) {
    327                 return $strip_result;
    328             }
     316        if ( apply_filters( 'image_strip_meta', $strip_meta ) ) {
     317            $this->strip_meta(); // Fail silently if not supported.
    329318        }
    330319
     
    335324             * unless we would be resampling to a scale smaller than 128x128.
    336325             */
    337             $resize_ratio = ( $dst_w / $this->size['width'] ) * ( $dst_h / $this->size['height'] );
    338             $sample_factor = 5;
    339 
    340             if ( $resize_ratio < .111 && ( $dst_w * $sample_factor > 128 && $dst_h * $sample_factor > 128 ) ) {
    341                 $this->image->sampleImage( $dst_w * $sample_factor, $dst_h * $sample_factor );
    342             }
    343 
    344             // Resize to the final output size.
    345             $this->image->setOption( 'filter:support', '2.0' );
    346             $this->image->resizeImage( $dst_w, $dst_h, $filter, 1 );
     326            if ( is_callable( array( $this->image, 'sampleImage' ) ) ) {
     327                $resize_ratio = ( $dst_w / $this->size['width'] ) * ( $dst_h / $this->size['height'] );
     328                $sample_factor = 5;
     329
     330                if ( $resize_ratio < .111 && ( $dst_w * $sample_factor > 128 && $dst_h * $sample_factor > 128 ) ) {
     331                    $this->image->sampleImage( $dst_w * $sample_factor, $dst_h * $sample_factor );
     332                }
     333            }
     334
     335            /*
     336             * Use resizeImage() when it's available and a valid filter value is set.
     337             * Otherwise, fall back to the scaleImage() method for resizing, which
     338             * results in better image quality over resizeImage() with default filter
     339             * settings and retains backwards compatibility with pre 4.5 functionality.
     340             */
     341            if ( is_callable( array( $this->image, 'resizeImage' ) ) && $filter ) {
     342                $this->image->setOption( 'filter:support', '2.0' );
     343                $this->image->resizeImage( $dst_w, $dst_h, $filter, 1 );
     344            } else {
     345                $this->image->scaleImage( $dst_w, $dst_h );
     346            }
    347347
    348348            // Set appropriate quality settings after resizing.
    349349            if ( 'image/jpeg' == $this->mime_type ) {
    350                 $this->image->unsharpMaskImage( 0.25, 0.25, 8, 0.065 );
     350                if ( is_callable( array( $this->image, 'unsharpMaskImage' ) ) ) {
     351                    $this->image->unsharpMaskImage( 0.25, 0.25, 8, 0.065 );
     352                }
     353
    351354                $this->image->setOption( 'jpeg:fancy-upsampling', 'off' );
    352355            }
     
    359362            }
    360363
    361             /**
     364            /*
    362365             * If alpha channel is not defined, set it opaque.
    363366             *
     
    365368             * has been compiled against ImageMagick version 6.4.0 or newer.
    366369             */
    367             if ( method_exists( $this->image, 'getImageAlphaChannel') && $this->image->getImageAlphaChannel() === Imagick::ALPHACHANNEL_UNDEFINED ) {
    368                 $this->image->setImageAlphaChannel( Imagick::ALPHACHANNEL_OPAQUE );
    369             }
    370 
    371             // Limit the  bit depth of resized images to 8 bits per channel.
    372             if ( 8 < $this->image->getImageDepth() ) {
    373                 $this->image->setImageDepth( 8 );
    374             }
    375 
    376             $this->image->setInterlaceScheme( Imagick::INTERLACE_NO );
     370            if ( is_callable( array( $this->image, 'getImageAlphaChannel' ) )
     371                && is_callable( array( $this->image, 'setImageAlphaChannel' ) )
     372                && defined( Imagick::ALPHACHANNEL_UNDEFINED )
     373                && defined( Imagick::ALPHACHANNEL_OPAQUE )
     374            ) {
     375                if ( $this->image->getImageAlphaChannel() === Imagick::ALPHACHANNEL_UNDEFINED ) {
     376                    $this->image->setImageAlphaChannel( Imagick::ALPHACHANNEL_OPAQUE );
     377                }
     378            }
     379
     380            // Limit the bit depth of resized images to 8 bits per channel.
     381            if ( is_callable( array( $this->image, 'getImageDepth' ) ) && is_callable( array( $this->image, 'setImageDepth' ) ) ) {
     382                if ( 8 < $this->image->getImageDepth() ) {
     383                    $this->image->setImageDepth( 8 );
     384                }
     385            }
     386
     387            if ( is_callable( array( $this->image, 'setInterlaceScheme' ) ) && defined( 'Imagick::INTERLACE_NO' ) ) {
     388                $this->image->setInterlaceScheme( Imagick::INTERLACE_NO );
     389            }
    377390
    378391        }
     
    663676     */
    664677    protected function strip_meta() {
     678
     679        if ( ! is_callable( array( $this->image, 'getImageProfiles' ) ) ) {
     680            return new WP_Error( 'image_strip_meta_error', __('Imagick::getImageProfiles() is required to strip image meta.') );
     681        }
     682
     683        if ( ! is_callable( array( $this->image, 'removeImageProfile' ) ) ) {
     684            return new WP_Error( 'image_strip_meta_error', __('Imagick::removeImageProfile() is required to strip image meta.') );
     685        }
     686
     687        /*
     688         * Protect a few profiles from being stripped for the following reasons:
     689         *
     690         * - icc:  Color profile information
     691         * - icm:  Color profile information
     692         * - iptc: Copyright data
     693         * - exif: Orientation data
     694         * - xmp:  Rights usage data
     695         */
     696        $protected_profiles = array(
     697            'icc',
     698            'icm',
     699            'iptc',
     700            'exif',
     701            'xmp',
     702        );
     703
    665704        try {
    666705            // Strip profiles.
    667706            foreach ( $this->image->getImageProfiles( '*', true ) as $key => $value ) {
    668                 if ( $key != 'icc' && $key != 'icm' ) {
     707                if ( ! in_array( $key, $protected_profiles ) ) {
    669708                    $this->image->removeImageProfile( $key );
    670709                }
    671710            }
    672711
    673             // Strip image properties.
    674             if ( method_exists( $this->image, 'deleteImageProperty' ) ) {
    675                 $this->image->deleteImageProperty( 'comment' );
    676                 $this->image->deleteImageProperty( 'Thumb::URI' );
    677                 $this->image->deleteImageProperty( 'Thumb::MTime' );
    678                 $this->image->deleteImageProperty( 'Thumb::Size' );
    679                 $this->image->deleteImageProperty( 'Thumb::Mimetype' );
    680                 $this->image->deleteImageProperty( 'software' );
    681                 $this->image->deleteImageProperty( 'Thumb::Image::Width' );
    682                 $this->image->deleteImageProperty( 'Thumb::Image::Height' );
    683                 $this->image->deleteImageProperty( 'Thumb::Document::Pages' );
    684             } else {
    685                 $this->image->setImageProperty( 'comment', '' );
    686                 $this->image->setImageProperty( 'Thumb::URI', '' );
    687                 $this->image->setImageProperty( 'Thumb::MTime', '' );
    688                 $this->image->setImageProperty( 'Thumb::Size', '' );
    689                 $this->image->setImageProperty( 'Thumb::Mimetype', '' );
    690                 $this->image->setImageProperty( 'software', '' );
    691                 $this->image->setImageProperty( 'Thumb::Image::Width', '' );
    692                 $this->image->setImageProperty( 'Thumb::Image::Height', '' );
    693                 $this->image->setImageProperty( 'Thumb::Document::Pages', '' );
    694             }
    695712        } catch ( Exception $e ) {
    696713            return new WP_Error( 'image_strip_meta_error', $e->getMessage() );
Note: See TracChangeset for help on using the changeset viewer.