WordPress.org

Make WordPress Core

Changeset 36891


Ignore:
Timestamp:
03/09/16 04:43:40 (16 months 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.