WordPress.org

Make WordPress Core

Ticket #23331: 23331.2.diff

File 23331.2.diff, 12.3 KB (added by markoheijnen, 13 months ago)

Change version number to 3.6.0 and also add [23750] to this patch

  • new file wp-includes/class-wp-image-editor-gmagick.php

    diff --git wp-includes/class-wp-image-editor-gmagick.php wp-includes/class-wp-image-editor-gmagick.php
    new file mode 100644
    index 0000000..e326ac3
    - +  
     1<?php 
     2/** 
     3 * WordPress Gmagick Image Editor 
     4 * 
     5 * @package WordPress 
     6 * @subpackage Image_Editor 
     7 */ 
     8 
     9/** 
     10 * WordPress Image Editor Class for Image Manipulation through Gmagick PHP Module 
     11 * 
     12 * @since 3.6.0 
     13 * @package WordPress 
     14 * @subpackage Image_Editor 
     15 * @uses WP_Image_Editor Extends class 
     16 */ 
     17class WP_Image_Editor_Gmagick extends WP_Image_Editor { 
     18 
     19        protected $image = null; // Gmagick Object 
     20 
     21        function __destruct() { 
     22                if ( $this->image ) { 
     23                        // we don't need the original in memory anymore 
     24                        $this->image->clear(); 
     25                        $this->image->destroy(); 
     26                } 
     27        } 
     28 
     29        /** 
     30         * Checks to see if current environment supports Gmagick. 
     31         * 
     32         * @since 3.6.0 
     33         * @access public 
     34         * 
     35         * @return boolean 
     36         */ 
     37        public static function test( $args = array() ) { 
     38                // Test Gmagick's extension and class. 
     39                if ( ! extension_loaded( 'gmagick' ) || ! class_exists( 'Gmagick' ) ) 
     40                        return false; 
     41 
     42                if ( array_diff( array( 'setcompressionquality', 'getimage' ), get_class_methods( 'Gmagick' ) ) ) 
     43                        return false; 
     44 
     45                return true; 
     46        } 
     47 
     48        /** 
     49         * Checks to see if editor supports the mime-type specified. 
     50         * 
     51         * @since 3.6.0 
     52         * @access public 
     53         * 
     54         * @param string $mime_type 
     55         * @return boolean 
     56         */ 
     57        public static function supports_mime_type( $mime_type ) { 
     58                $gmagick_extension = strtoupper( self::get_extension( $mime_type ) ); 
     59 
     60                if ( ! $gmagick_extension ) 
     61                        return false; 
     62 
     63                // setimageindex is optional unless mime is an animated format. 
     64                // Here, we just say no if you are missing it and aren't loading a jpeg. 
     65                if ( ! method_exists( 'Gmagick', 'setimageindex' ) && $mime_type != 'image/jpeg' ) 
     66                                return false; 
     67 
     68                try { 
     69                        $gmagick = new Gmagick; 
     70                        return ( (bool) $gmagick->queryformats( $gmagick_extension ) ); 
     71                } 
     72                catch ( Exception $e ) { 
     73                        return false; 
     74                } 
     75        } 
     76 
     77        /** 
     78         * Loads image from $this->file into new Gmagick Object. 
     79         * 
     80         * @since 3.6.0 
     81         * @access protected 
     82         * 
     83         * @return boolean|WP_Error True if loaded; WP_Error on failure. 
     84         */ 
     85        public function load() { 
     86                if ( $this->image ) 
     87                        return true; 
     88 
     89                if ( ! is_file( $this->file ) && ! preg_match( '|^https?://|', $this->file ) ) 
     90                        return new WP_Error( 'error_loading_image', __('File doesn&#8217;t exist?'), $this->file ); 
     91 
     92                try { 
     93                        $this->image = new Gmagick( $this->file ); 
     94 
     95                        // Select the first frame to handle animated images properly 
     96                        if ( is_callable( array( $this->image, 'setimageindex' ) ) ) 
     97                                $this->image->setimageindex(0); 
     98 
     99                        $this->mime_type = $this->get_mime_type( $this->image->getimageformat() ); 
     100                } 
     101                catch ( Exception $e ) { 
     102                        return new WP_Error( 'invalid_image', $e->getMessage(), $this->file ); 
     103                } 
     104 
     105                $updated_size = $this->update_size(); 
     106                if ( is_wp_error( $updated_size ) ) 
     107                                return $updated_size; 
     108 
     109                return $this->set_quality(); 
     110        } 
     111 
     112        /** 
     113         * Sets Image Compression quality on a 1-100% scale. 
     114         * 
     115         * @since 3.6.0 
     116         * @access public 
     117         * 
     118         * @param int $quality Compression Quality. Range: [1,100] 
     119         * @return boolean|WP_Error 
     120         */ 
     121        public function set_quality( $quality = null ) { 
     122                if ( !$quality ) 
     123                        $quality = $this->quality; 
     124 
     125                try { 
     126                        if( 'image/jpeg' == $this->mime_type ) { 
     127                                $this->image->setcompressionquality( apply_filters( 'jpeg_quality', $quality, 'image_resize' ) ); 
     128                        } 
     129                        else { 
     130                                $this->image->setcompressionquality( $quality ); 
     131                        } 
     132                } 
     133                catch ( Exception $e ) { 
     134                        return new WP_Error( 'image_quality_error', $e->getMessage() ); 
     135                } 
     136 
     137                return parent::set_quality( $quality ); 
     138        } 
     139 
     140        /** 
     141         * Sets or updates current image size. 
     142         * 
     143         * @since 3.6.0 
     144         * @access protected 
     145         * 
     146         * @param int $width 
     147         * @param int $height 
     148         */ 
     149        protected function update_size( $width = null, $height = null ) { 
     150                $size = null; 
     151                if ( !$width || !$height ) { 
     152                        try { 
     153                                $size = array( 
     154                                        'width' => $this->image->getimagewidth(), 
     155                                        'height' => $this->image->getimageheight() 
     156                                ); 
     157                        } 
     158                        catch ( Exception $e ) { 
     159                                return new WP_Error( 'invalid_image', __('Could not read image size'), $this->file ); 
     160                        } 
     161                } 
     162 
     163                if ( ! $width ) 
     164                        $width = $size['width']; 
     165 
     166                if ( ! $height ) 
     167                        $height = $size['height']; 
     168 
     169                return parent::update_size( $width, $height ); 
     170        } 
     171 
     172        /** 
     173         * Resizes current image. 
     174         * 
     175         * @since 3.6.0 
     176         * @access public 
     177         * 
     178         * @param int $max_w 
     179         * @param int $max_h 
     180         * @param boolean $crop 
     181         * @return boolean|WP_Error 
     182         */ 
     183        public function resize( $max_w, $max_h, $crop = false ) { 
     184                if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) ) 
     185                        return true; 
     186 
     187                $dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop ); 
     188                if ( ! $dims ) 
     189                        return new WP_Error( 'error_getting_dimensions', __('Could not calculate resized image dimensions') ); 
     190                list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims; 
     191 
     192                if ( $crop ) { 
     193                        return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h ); 
     194                } 
     195 
     196                try { 
     197                        /** 
     198                         * @TODO: Thumbnail is more efficient for imagick, given a newer version of Imagemagick. 
     199                         * Is this also true for gmagick and what are the rules here 
     200                         * $this->image->thumbnailimage( $dst_w, $dst_h ); 
     201                         */ 
     202                        $this->image->scaleimage( $dst_w, $dst_h ); 
     203                } 
     204                catch ( Exception $e ) { 
     205                        return new WP_Error( 'image_resize_error', $e->getMessage() ); 
     206                } 
     207 
     208                return $this->update_size( $dst_w, $dst_h ); 
     209        } 
     210 
     211        /** 
     212         * Processes current image and saves to disk 
     213         * multiple sizes from single source. 
     214         * 
     215         * @since 3.6.0 
     216         * @access public 
     217         * 
     218         * @param array $sizes { {'width'=>int, 'height'=>int, 'crop'=>bool}, ... } 
     219         * @return array 
     220         */ 
     221        public function multi_resize( $sizes ) { 
     222                $metadata = array(); 
     223                $orig_size = $this->size; 
     224                $orig_image = $this->image->getimage(); 
     225 
     226                foreach ( $sizes as $size => $size_data ) { 
     227                        if ( ! $this->image ) 
     228                                $this->image = $orig_image->getimage(); 
     229 
     230                        $resize_result = $this->resize( $size_data['width'], $size_data['height'], $size_data['crop'] ); 
     231 
     232                        if( ! is_wp_error( $resize_result ) ) { 
     233                                $resized = $this->_save( $this->image ); 
     234 
     235                                $this->image->clear(); 
     236                                $this->image->destroy(); 
     237                                $this->image = null; 
     238 
     239                                if ( ! is_wp_error( $resized ) ) { 
     240                                        unset( $resized['path'] ); 
     241                                        $metadata[$size] = $resized; 
     242                                } 
     243                        } 
     244 
     245                        $this->size = $orig_size; 
     246                } 
     247 
     248                $this->image = $orig_image; 
     249 
     250                return $metadata; 
     251        } 
     252 
     253        /** 
     254         * Crops Image. 
     255         * 
     256         * @since 3.6.0 
     257         * @access public 
     258         * 
     259         * @param string|int $src The source file or Attachment ID. 
     260         * @param int $src_x The start x position to crop from. 
     261         * @param int $src_y The start y position to crop from. 
     262         * @param int $src_w The width to crop. 
     263         * @param int $src_h The height to crop. 
     264         * @param int $dst_w Optional. The destination width. 
     265         * @param int $dst_h Optional. The destination height. 
     266         * @param boolean $src_abs Optional. If the source crop points are absolute. 
     267         * @return boolean|WP_Error 
     268         */ 
     269        public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) { 
     270                if ( $src_abs ) { 
     271                        $src_w -= $src_x; 
     272                        $src_h -= $src_y; 
     273                } 
     274 
     275                try { 
     276                        $this->image->cropimage( $src_w, $src_h, $src_x, $src_y ); 
     277 
     278                        if ( $dst_w || $dst_h ) { 
     279                                // If destination width/height isn't specified, use same as 
     280                                // width/height from source. 
     281                                if ( ! $dst_w ) 
     282                                        $dst_w = $src_w; 
     283                                if ( ! $dst_h ) 
     284                                        $dst_h = $src_h; 
     285 
     286                                $this->image->scaleimage( $dst_w, $dst_h ); 
     287                                return $this->update_size(); 
     288                        } 
     289                } 
     290                catch ( Exception $e ) { 
     291                        return new WP_Error( 'image_crop_error', $e->getMessage() ); 
     292                } 
     293                return $this->update_size(); 
     294        } 
     295 
     296        /** 
     297         * Rotates current image counter-clockwise by $angle. 
     298         * 
     299         * @since 3.6.0 
     300         * @access public 
     301         * 
     302         * @param float $angle 
     303         * @return boolean|WP_Error 
     304         */ 
     305        public function rotate( $angle ) { 
     306                /** 
     307                 * $angle is 360-$angle because Gmagick rotates clockwise 
     308                 * (GD rotates counter-clockwise) 
     309                 */ 
     310                try { 
     311                        $this->image->rotateimage( new GmagickPixel('none'), 360 - $angle ); 
     312                } 
     313                catch ( Exception $e ) { 
     314                        return new WP_Error( 'image_rotate_error', $e->getMessage() ); 
     315                } 
     316                return $this->update_size(); 
     317        } 
     318 
     319        /** 
     320         * Flips current image. 
     321         * 
     322         * @since 3.6.0 
     323         * @access public 
     324         * 
     325         * @param boolean $horz Flip along Horizontal Axis 
     326         * @param boolean $vert Flip along Vertical Axis 
     327         * @returns boolean|WP_Error 
     328         */ 
     329        public function flip( $horz, $vert ) { 
     330                try { 
     331                        if ( $horz ) 
     332                                $this->image->flipimage(); 
     333 
     334                        if ( $vert ) 
     335                                $this->image->flopimage(); 
     336                } 
     337                catch ( Exception $e ) { 
     338                        return new WP_Error( 'image_flip_error', $e->getMessage() ); 
     339                } 
     340                return true; 
     341        } 
     342 
     343        /** 
     344         * Saves current image to file. 
     345         * 
     346         * @since 3.6.0 
     347         * @access public 
     348         * 
     349         * @param string $destfilename 
     350         * @param string $mime_type 
     351         * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string} 
     352         */ 
     353        public function save( $destfilename = null, $mime_type = null ) { 
     354                $saved = $this->_save( $this->image, $destfilename, $mime_type ); 
     355 
     356                if ( ! is_wp_error( $saved ) ) { 
     357                        $this->file = $saved['path']; 
     358                        $this->mime_type = $saved['mime-type']; 
     359 
     360                        try { 
     361                                $this->image->setimageformat( strtoupper( $this->get_extension( $this->mime_type ) ) ); 
     362                        } 
     363                        catch ( Exception $e ) { 
     364                                return new WP_Error( 'image_save_error', $e->getMessage(), $this->file ); 
     365                        } 
     366                } 
     367 
     368                return $saved; 
     369        } 
     370 
     371        protected function _save( $image, $filename = null, $mime_type = null ) { 
     372                list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type ); 
     373 
     374                if ( ! $filename ) 
     375                        $filename = $this->generate_filename( null, null, $extension ); 
     376 
     377                try { 
     378                        // Store initial Format 
     379                        $orig_format = $this->image->getimageformat(); 
     380 
     381                        $this->image->setimageformat( strtoupper( $this->get_extension( $mime_type ) ) ); 
     382                        $this->make_image( $filename, array( $image, 'writeImage' ), array( $filename ) ); 
     383 
     384                        // Reset original Format 
     385                        $this->image->setimageformat( $orig_format ); 
     386                } 
     387                catch ( Exception $e ) { 
     388                        return new WP_Error( 'image_save_error', $e->getMessage(), $filename ); 
     389                } 
     390 
     391                // Set correct file permissions 
     392                $stat = stat( dirname( $filename ) ); 
     393                $perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits 
     394                @ chmod( $filename, $perms ); 
     395 
     396                return array( 
     397                        'path' => $filename, 
     398                        'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $filename ) ), 
     399                        'width' => $this->size['width'], 
     400                        'height' => $this->size['height'], 
     401                        'mime-type' => $mime_type, 
     402                ); 
     403        } 
     404 
     405        /** 
     406         * Streams current image to browser. 
     407         * 
     408         * @since 3.6.0 
     409         * @access public 
     410         * 
     411         * @param string $mime_type 
     412         * @return boolean|WP_Error 
     413         */ 
     414        public function stream( $mime_type = null ) { 
     415                list( $filename, $extension, $mime_type ) = $this->get_output_format( null, $mime_type ); 
     416 
     417                try { 
     418                        // Temporarily change format for stream 
     419                        $this->image->setimageformat( strtoupper( $extension ) ); 
     420 
     421                        // Output stream of image content 
     422                        header( "Content-Type: $mime_type" ); 
     423                        print $this->image->getimageblob(); 
     424 
     425                        // Reset Image to original Format 
     426                        $this->image->setimageformat( $this->get_extension( $this->mime_type ) ); 
     427                } 
     428                catch ( Exception $e ) { 
     429                        return new WP_Error( 'image_stream_error', $e->getMessage() ); 
     430                } 
     431 
     432                return true; 
     433        } 
     434} 
     435 No newline at end of file 
  • wp-includes/media.php

    diff --git wp-includes/media.php wp-includes/media.php
    index 682ffbb..e0c6357 100644
    function _wp_image_editor_choose( $args = array() ) { 
    12221222        require_once ABSPATH . WPINC . '/class-wp-image-editor.php'; 
    12231223        require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php'; 
    12241224        require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php'; 
     1225        require_once ABSPATH . WPINC . '/class-wp-image-editor-gmagick.php'; 
    12251226 
    12261227        $implementations = apply_filters( 'wp_image_editors', 
    1227                 array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) ); 
     1228                array( 'WP_Image_Editor_Gmagick', 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) ); 
    12281229 
    12291230        foreach ( $implementations as $implementation ) { 
    12301231                if ( ! call_user_func( array( $implementation, 'test' ), $args ) )