Make WordPress Core


Ignore:
Timestamp:
10/01/2012 08:59:06 PM (12 years ago)
Author:
ryan
Message:

Introduce WP_Image_Editor, WP_Image_Editor_Imagick, and WP_Image_Editor_GD. Abstracts image editing API and adds support for ImageMagick.

Props DH-Shredder, kurtpayne, markoheijnen
see #6821

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-admin/includes/image-edit.php

    r21808 r22094  
    198198}
    199199
    200 function wp_stream_image($image, $mime_type, $post_id) {
    201     $image = apply_filters('image_save_pre', $image, $post_id);
    202 
    203     switch ( $mime_type ) {
    204         case 'image/jpeg':
    205             header('Content-Type: image/jpeg');
    206             return imagejpeg($image, null, 90);
    207         case 'image/png':
    208             header('Content-Type: image/png');
    209             return imagepng($image);
    210         case 'image/gif':
    211             header('Content-Type: image/gif');
    212             return imagegif($image);
    213         default:
     200/**
     201 * Streams image in WP_Image_Editor to browser.
     202 * Provided for backcompat reasons
     203 *
     204 * @param WP_Image_Editor $image
     205 * @param string $mime_type
     206 * @param int $post_id
     207 * @return boolean
     208 */
     209function wp_stream_image( $image, $mime_type, $post_id ) {
     210    if ( $image instanceof WP_Image_Editor ) {
     211        $image = apply_filters('image_editor_save_pre', $image, $post_id);
     212
     213        if ( is_wp_error( $image->stream( $mime_type ) ) )
    214214            return false;
    215     }
    216 }
    217 
    218 function wp_save_image_file($filename, $image, $mime_type, $post_id) {
    219     $image = apply_filters('image_save_pre', $image, $post_id);
    220     $saved = apply_filters('wp_save_image_file', null, $filename, $image, $mime_type, $post_id);
    221     if ( null !== $saved )
    222         return $saved;
    223 
    224     switch ( $mime_type ) {
    225         case 'image/jpeg':
    226             return imagejpeg( $image, $filename, apply_filters( 'jpeg_quality', 90, 'edit_image' ) );
    227         case 'image/png':
    228             return imagepng($image, $filename);
    229         case 'image/gif':
    230             return imagegif($image, $filename);
    231         default:
    232             return false;
     215
     216        return true;
     217    } else {
     218        _deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
     219
     220        $image = apply_filters('image_save_pre', $image, $post_id);
     221
     222        switch ( $mime_type ) {
     223            case 'image/jpeg':
     224                header( 'Content-Type: image/jpeg' );
     225                return imagejpeg( $image, null, 90 );
     226            case 'image/png':
     227                header( 'Content-Type: image/png' );
     228                return imagepng( $image );
     229            case 'image/gif':
     230                header( 'Content-Type: image/gif' );
     231                return imagegif( $image );
     232            default:
     233                return false;
     234        }
     235    }
     236}
     237
     238/**
     239 * Saves Image to File
     240 * @TODO: Add mime_type support to WP_Image_Editor
     241 *
     242 * @param string $filename
     243 * @param WP_Image_Editor $image
     244 * @param string $mime_type
     245 * @param int $post_id
     246 * @return boolean
     247 */
     248function wp_save_image_file( $filename, $image, $mime_type, $post_id ) {
     249    if ( $image instanceof WP_Image_Editor ) {
     250        $image = apply_filters('image_editor_save_pre', $image, $post_id);
     251        $saved = apply_filters('wp_save_image_editor_file', null, $filename, $image, $mime_type, $post_id);
     252
     253        if ( null !== $saved )
     254            return $saved;
     255
     256        return $image->save( $filename, $mime_type );
     257    } else {
     258        _deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
     259
     260        $image = apply_filters('image_save_pre', $image, $post_id);
     261        $saved = apply_filters('wp_save_image_file', null, $filename, $image, $mime_type, $post_id);
     262
     263        if ( null !== $saved )
     264            return $saved;
     265
     266        switch ( $mime_type ) {
     267            case 'image/jpeg':
     268                return imagejpeg( $image, $filename, apply_filters( 'jpeg_quality', 90, 'edit_image' ) );
     269            case 'image/png':
     270                return imagepng( $image, $filename );
     271            case 'image/gif':
     272                return imagegif( $image, $filename );
     273            default:
     274                return false;
     275        }
    233276    }
    234277}
     
    239282}
    240283
     284// @TODO: Returns GD resource, but is NOT public
    241285function _rotate_image_resource($img, $angle) {
     286    _deprecated_function( __FUNCTION__, '3.5', __( 'Use WP_Image_Editor::rotate' ) );
    242287    if ( function_exists('imagerotate') ) {
    243288        $rotated = imagerotate($img, $angle, 0);
     
    250295}
    251296
     297/**
     298 * @TODO: Only used within image_edit_apply_changes
     299 *        and receives/returns GD Resource.
     300 *        Consider removal.
     301 *
     302 * @param GD_Resource $img
     303 * @param boolean $horz
     304 * @param boolean $vert
     305 * @return GD_Resource
     306 */
    252307function _flip_image_resource($img, $horz, $vert) {
     308    _deprecated_function( __FUNCTION__, '3.5', __( 'Use WP_Image_Editor::flip' ) );
    253309    $w = imagesx($img);
    254310    $h = imagesy($img);
     
    268324}
    269325
     326/**
     327 * @TODO: Only used within image_edit_apply_changes
     328 *        and receives/returns GD Resource.
     329 *        Consider removal.
     330 *
     331 * @param GD_Resource $img
     332 * @param float $x
     333 * @param float $y
     334 * @param float $w
     335 * @param float $h
     336 * @return GD_Resource
     337 */
    270338function _crop_image_resource($img, $x, $y, $w, $h) {
    271339    $dst = wp_imagecreatetruecolor($w, $h);
     
    279347}
    280348
    281 function image_edit_apply_changes($img, $changes) {
     349/**
     350 * Performs group of changes on Editor specified.
     351 *
     352 * @param WP_Image_Editor $image
     353 * @param type $changes
     354 * @return WP_Image_Editor
     355 */
     356function image_edit_apply_changes( $image, $changes ) {
     357    if ( is_resource( $image ) )
     358        _deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
    282359
    283360    if ( !is_array($changes) )
    284         return $img;
     361        return $image;
    285362
    286363    // expand change operations
     
    327404
    328405    // image resource before applying the changes
    329     $img = apply_filters('image_edit_before_change', $img, $changes);
     406    if ( $image instanceof WP_Image_Editor )
     407        $image = apply_filters('wp_image_editor_before_change', $image, $changes);
     408    elseif ( is_resource( $image ) )
     409        $image = apply_filters('image_edit_before_change', $image, $changes);
    330410
    331411    foreach ( $changes as $operation ) {
    332412        switch ( $operation->type ) {
    333413            case 'rotate':
    334                 if ( $operation->angle != 0 )
    335                     $img = _rotate_image_resource($img, $operation->angle);
     414                if ( $operation->angle != 0 ) {
     415                    if ( $image instanceof WP_Image_Editor )
     416                        $image->rotate( $operation->angle );
     417                    else
     418                        $image = _rotate_image_resource( $image, $operation->angle );
     419                }
    336420                break;
    337421            case 'flip':
    338422                if ( $operation->axis != 0 )
    339                     $img = _flip_image_resource($img, ($operation->axis & 1) != 0, ($operation->axis & 2) != 0);
     423                    if ( $image instanceof WP_Image_Editor )
     424                        $image->flip( ($operation->axis & 1) != 0, ($operation->axis & 2) != 0 );
     425                    else
     426                        $image = _flip_image_resource( $image, ( $operation->axis & 1 ) != 0, ( $operation->axis & 2 ) != 0 );
    340427                break;
    341428            case 'crop':
    342429                $sel = $operation->sel;
    343                 $scale = 1 / _image_get_preview_ratio( imagesx($img), imagesy($img) ); // discard preview scaling
    344                 $img = _crop_image_resource($img, $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale);
     430
     431                if ( $image instanceof WP_Image_Editor ) {
     432                    $size = $image->get_size();
     433                    $w = $size['width'];
     434                    $h = $size['height'];
     435
     436                    $scale = 1 / _image_get_preview_ratio( $w, $h ); // discard preview scaling
     437                    $image->crop( $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
     438                } else {
     439                    $scale = 1 / _image_get_preview_ratio( imagesx( $image ), imagesy( $image ) ); // discard preview scaling
     440                    $image = _crop_image_resource( $image, $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
     441                }
    345442                break;
    346443        }
    347444    }
    348445
    349     return $img;
    350 }
    351 
    352 function stream_preview_image($post_id) {
    353     $post = get_post($post_id);
     446    return $image;
     447}
     448
     449
     450/**
     451 * Streams image in post to browser, along with enqueued changes
     452 * in $_REQUEST['history']
     453 *
     454 * @param int $post_id
     455 * @return boolean
     456 */
     457function stream_preview_image( $post_id ) {
     458    $post = get_post( $post_id );
    354459    @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
    355     $img = load_image_to_edit( $post_id, $post->post_mime_type, array(400, 400) );
    356 
    357     if ( !is_resource($img) )
    358         return false;
     460
     461    $img = WP_Image_Editor::get_instance( _load_image_to_edit_path( $post_id ) );
     462
     463    if ( is_wp_error( $img ) )
     464        return false;
    359465
    360466    $changes = !empty($_REQUEST['history']) ? json_decode( stripslashes($_REQUEST['history']) ) : null;
    361467    if ( $changes )
    362         $img = image_edit_apply_changes($img, $changes);
     468        $img = image_edit_apply_changes( $img, $changes );
    363469
    364470    // scale the image
    365     $w = imagesx($img);
    366     $h = imagesy($img);
    367     $ratio = _image_get_preview_ratio($w, $h);
     471    $size = $img->get_size();
     472    $w = $size['width'];
     473    $h = $size['height'];
     474
     475    $ratio = _image_get_preview_ratio( $w, $h );
    368476    $w2 = $w * $ratio;
    369477    $h2 = $h * $ratio;
    370478
    371     $preview = wp_imagecreatetruecolor($w2, $h2);
    372     imagecopyresampled( $preview, $img, 0, 0, 0, 0, $w2, $h2, $w, $h );
    373     wp_stream_image($preview, $post->post_mime_type, $post_id);
    374 
    375     imagedestroy($preview);
    376     imagedestroy($img);
    377     return true;
     479    if ( is_wp_error( $img->resize( $w2, $h2 ) ) )
     480        return false;
     481
     482    return wp_stream_image( $img, $post->post_mime_type, $post_id );
    378483}
    379484
     
    451556}
    452557
    453 function wp_save_image($post_id) {
     558/**
     559 * Saves image to post along with enqueued changes
     560 * in $_REQUEST['history']
     561 *
     562 * @param int $post_id
     563 * @return \stdClass
     564 */
     565function wp_save_image( $post_id ) {
    454566    $return = new stdClass;
    455567    $success = $delete = $scaled = $nocrop = false;
    456     $post = get_post($post_id);
    457     @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
    458     $img = load_image_to_edit($post_id, $post->post_mime_type);
    459 
    460     if ( !is_resource($img) ) {
     568    $post = get_post( $post_id );
     569
     570    $img = WP_Image_Editor::get_instance( _load_image_to_edit_path( $post_id, 'full' ) );
     571    if ( !$img ) {
    461572        $return->error = esc_js( __('Unable to create new image.') );
    462573        return $return;
     
    469580
    470581    if ( $scale && $fwidth > 0 && $fheight > 0 ) {
    471         $sX = imagesx($img);
    472         $sY = imagesy($img);
     582        $size = $img->get_size();
     583        $sX = $size['width'];
     584        $sY = $size['height'];
    473585
    474586        // check if it has roughly the same w / h ratio
     
    476588        if ( -0.1 < $diff && $diff < 0.1 ) {
    477589            // scale the full size image
    478             $dst = wp_imagecreatetruecolor($fwidth, $fheight);
    479             if ( imagecopyresampled( $dst, $img, 0, 0, 0, 0, $fwidth, $fheight, $sX, $sY ) ) {
    480                 imagedestroy($img);
    481                 $img = $dst;
     590            if ( $img->resize( $fwidth, $fheight ) )
    482591                $scaled = true;
    483             }
    484592        }
    485593
     
    552660            $backup_sizes[$tag] = array('width' => $meta['width'], 'height' => $meta['height'], 'file' => $path_parts['basename']);
    553661
    554         $success = update_attached_file($post_id, $new_path);
    555 
    556         $meta['file'] = _wp_relative_upload_path($new_path);
    557         $meta['width'] = imagesx($img);
    558         $meta['height'] = imagesy($img);
     662        $success = update_attached_file( $post_id, $new_path );
     663
     664        $meta['file'] = _wp_relative_upload_path( $new_path );
     665
     666        $size = $img->get_size();
     667        $meta['width'] = $size['width'];
     668        $meta['height'] = $size['height'];
    559669
    560670        if ( $success && ('nothumb' == $target || 'all' == $target) ) {
     
    571681    }
    572682
    573     if ( isset($sizes) ) {
     683    if ( isset( $sizes ) ) {
     684        $_sizes = array();
     685
    574686        foreach ( $sizes as $size ) {
    575687            $tag = false;
    576             if ( isset($meta['sizes'][$size]) ) {
     688            if ( isset( $meta['sizes'][$size] ) ) {
    577689                if ( isset($backup_sizes["$size-orig"]) ) {
    578690                    if ( ( !defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE ) && $backup_sizes["$size-orig"]['file'] != $meta['sizes'][$size]['file'] )
     
    587699
    588700            $crop = $nocrop ? false : get_option("{$size}_crop");
    589             $resized = image_make_intermediate_size($new_path, get_option("{$size}_size_w"), get_option("{$size}_size_h"), $crop );
    590 
    591             if ( $resized )
    592                 $meta['sizes'][$size] = $resized;
    593             else
    594                 unset($meta['sizes'][$size]);
    595         }
    596     }
     701            $_sizes[ $size ] = array( 'width' => get_option("{$size}_size_w"), 'height' => get_option("{$size}_size_h"), 'crop' => $crop );
     702        }
     703
     704        $meta['sizes'] = $img->multi_resize( $_sizes );
     705    }
     706
     707    unset( $img );
    597708
    598709    if ( $success ) {
    599         wp_update_attachment_metadata($post_id, $meta);
     710        wp_update_attachment_metadata( $post_id, $meta );
    600711        update_post_meta( $post_id, '_wp_attachment_backup_sizes', $backup_sizes);
    601712
     
    613724    if ( $delete ) {
    614725        $delpath = apply_filters('wp_delete_file', $new_path);
    615         @unlink($delpath);
    616     }
    617 
    618     imagedestroy($img);
     726        @unlink( $delpath );
     727    }
    619728
    620729    $return->msg = esc_js( __('Image saved') );
Note: See TracChangeset for help on using the changeset viewer.