Make WordPress Core


Ignore:
Timestamp:
03/09/2016 04:43:40 AM (11 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.