]> scripts.mit.edu Git - autoinstalls/wordpress.git/blobdiff - wp-admin/includes/image-edit.php
WordPress 3.8.3
[autoinstalls/wordpress.git] / wp-admin / includes / image-edit.php
index e871ae5e5811a2e6dbffb562dce2bcec9a5b3ad8..f25546e5e7ed6b95ee118ee52da0506536a2752a 100644 (file)
@@ -13,7 +13,7 @@ function wp_image_editor($post_id, $msg = false) {
        $sub_sizes = isset($meta['sizes']) && is_array($meta['sizes']);
        $note = '';
 
-       if ( is_array($meta) && isset($meta['width']) )
+       if ( isset( $meta['width'], $meta['height'] ) )
                $big = max( $meta['width'], $meta['height'] );
        else
                die( __('Image data does not exist. Please re-upload the image.') );
@@ -21,8 +21,9 @@ function wp_image_editor($post_id, $msg = false) {
        $sizer = $big > 400 ? 400 / $big : 1;
 
        $backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
-       $can_restore = !empty($backup_sizes) && isset($backup_sizes['full-orig'])
-               && $backup_sizes['full-orig']['file'] != basename($meta['file']);
+       $can_restore = false;
+       if ( ! empty( $backup_sizes ) && isset( $backup_sizes['full-orig'], $meta['file'] ) )
+               $can_restore = $backup_sizes['full-orig']['file'] != basename( $meta['file'] );
 
        if ( $msg ) {
                if ( isset($msg->error) )
@@ -40,14 +41,14 @@ function wp_image_editor($post_id, $msg = false) {
                <div onclick="imageEdit.crop(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-crop disabled" title="<?php esc_attr_e( 'Crop' ); ?>"></div><?php
 
        // On some setups GD library does not provide imagerotate() - Ticket #11536
-       if ( function_exists('imagerotate') ) { ?>
+       if ( wp_image_editor_supports( array( 'mime_type' => get_post_mime_type( $post_id ), 'methods' => array( 'rotate' ) ) ) ) { ?>
                <div class="imgedit-rleft"  onclick="imageEdit.rotate( 90, <?php echo "$post_id, '$nonce'"; ?>, this)" title="<?php esc_attr_e( 'Rotate counter-clockwise' ); ?>"></div>
                <div class="imgedit-rright" onclick="imageEdit.rotate(-90, <?php echo "$post_id, '$nonce'"; ?>, this)" title="<?php esc_attr_e( 'Rotate clockwise' ); ?>"></div>
 <?php } else {
-               $note_gdlib = esc_attr__('Image rotation is not supported by your web host (function imagerotate() is missing)');
+               $note_no_rotate = esc_attr__('Image rotation is not supported by your web host.');
 ?>
-           <div class="imgedit-rleft disabled"  title="<?php echo $note_gdlib; ?>"></div>
-           <div class="imgedit-rright disabled" title="<?php echo $note_gdlib; ?>"></div>
+           <div class="imgedit-rleft disabled"  title="<?php echo $note_no_rotate; ?>"></div>
+           <div class="imgedit-rright disabled" title="<?php echo $note_no_rotate; ?>"></div>
 <?php } ?>
 
                <div onclick="imageEdit.flip(1, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-flipv" title="<?php esc_attr_e( 'Flip vertically' ); ?>"></div>
@@ -63,11 +64,11 @@ function wp_image_editor($post_id, $msg = false) {
        <input type="hidden" id="imgedit-history-<?php echo $post_id; ?>" value="" />
        <input type="hidden" id="imgedit-undone-<?php echo $post_id; ?>" value="0" />
        <input type="hidden" id="imgedit-selection-<?php echo $post_id; ?>" value="" />
-       <input type="hidden" id="imgedit-x-<?php echo $post_id; ?>" value="<?php echo $meta['width']; ?>" />
-       <input type="hidden" id="imgedit-y-<?php echo $post_id; ?>" value="<?php echo $meta['height']; ?>" />
+       <input type="hidden" id="imgedit-x-<?php echo $post_id; ?>" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />
+       <input type="hidden" id="imgedit-y-<?php echo $post_id; ?>" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
 
        <div id="imgedit-crop-<?php echo $post_id; ?>" class="imgedit-crop-wrap">
-       <img id="image-preview-<?php echo $post_id; ?>" onload="imageEdit.imgLoaded('<?php echo $post_id; ?>')" src="<?php echo admin_url('admin-ajax.php'); ?>?action=imgedit-preview&amp;_ajax_nonce=<?php echo $nonce; ?>&amp;postid=<?php echo $post_id; ?>&amp;rand=<?php echo rand(1, 99999); ?>" />
+       <img id="image-preview-<?php echo $post_id; ?>" onload="imageEdit.imgLoaded('<?php echo $post_id; ?>')" src="<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>?action=imgedit-preview&amp;_ajax_nonce=<?php echo $nonce; ?>&amp;postid=<?php echo $post_id; ?>&amp;rand=<?php echo rand(1, 99999); ?>" />
        </div>
 
        <div class="imgedit-submit">
@@ -81,10 +82,12 @@ function wp_image_editor($post_id, $msg = false) {
        <div class="imgedit-group-top">
                <a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><strong><?php _e('Scale Image'); ?></strong></a>
                <div class="imgedit-help">
-               <p><?php _e('You can proportionally scale the original image. For best results the scaling should be done before performing any other operations on it like crop, rotate, etc. Note that if you make the image larger it may become fuzzy.'); ?></p>
+               <p><?php _e('You can proportionally scale the original image. For best results the scaling should be done before performing any other operations on it like crop, rotate, etc. Note that images can only be scaled down, not up.'); ?></p>
+               <?php if ( isset( $meta['width'], $meta['height'] ) ): ?>
                <p><?php printf( __('Original dimensions %s'), $meta['width'] . '&times;' . $meta['height'] ); ?></p>
+               <?php endif ?>
                <div class="imgedit-submit">
-               <span class="nowrap"><input type="text" id="imgedit-scale-width-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" style="width:4em;" value="<?php echo $meta['width']; ?>" />&times;<input type="text" id="imgedit-scale-height-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" style="width:4em;" value="<?php echo $meta['height']; ?>" />
+               <span class="nowrap"><input type="text" id="imgedit-scale-width-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" style="width:4em;" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />&times;<input type="text" id="imgedit-scale-height-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" style="width:4em;" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
                <span class="imgedit-scale-warn" id="imgedit-scale-warn-<?php echo $post_id; ?>">!</span></span>
                <input type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'scale')" class="button-primary" value="<?php esc_attr_e( 'Scale' ); ?>" />
                </div>
@@ -118,14 +121,6 @@ function wp_image_editor($post_id, $msg = false) {
                <a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><?php _e('(help)'); ?></a>
                <div class="imgedit-help">
                <p><?php _e('The image can be cropped by clicking on it and dragging to select the desired part. While dragging the dimensions of the selection are displayed below.'); ?></p>
-               <strong><?php _e('Keyboard Shortcuts'); ?></strong>
-               <ul>
-               <li><?php _e('Arrow: move by 10px'); ?></li>
-               <li><?php _e('Shift + arrow: move by 1px'); ?></li>
-               <li><?php _e('Ctrl + arrow: resize by 10px'); ?></li>
-               <li><?php _e('Ctrl + Shift + arrow: resize by 1px'); ?></li>
-               <li><?php _e('Shift + drag: lock aspect ratio'); ?></li>
-               </ul>
 
                <p><strong><?php _e('Crop Aspect Ratio'); ?></strong><br />
                <?php _e('You can specify the crop selection aspect ratio then hold down the Shift key while dragging to lock it. The values can be 1:1 (square), 4:3, 16:9, etc. If there is a selection, specifying aspect ratio will set it immediately.'); ?></p>
@@ -191,83 +186,88 @@ function wp_image_editor($post_id, $msg = false) {
        </td></tr>
        </tbody></table>
        <div class="imgedit-wait" id="imgedit-wait-<?php echo $post_id; ?>"></div>
-       <script type="text/javascript">imageEdit.init(<?php echo $post_id; ?>);</script>
-       <div class="hidden" id="imgedit-leaving-<?php echo $post_id; ?>"><?php _e("There are unsaved changes that will be lost.  'OK' to continue, 'Cancel' to return to the Image Editor."); ?></div>
+       <script type="text/javascript">jQuery( function() { imageEdit.init(<?php echo $post_id; ?>); });</script>
+       <div class="hidden" id="imgedit-leaving-<?php echo $post_id; ?>"><?php _e("There are unsaved changes that will be lost. 'OK' to continue, 'Cancel' to return to the Image Editor."); ?></div>
        </div>
 <?php
 }
 
-function load_image_to_edit($post_id, $mime_type, $size = 'full') {
-       $filepath = get_attached_file($post_id);
-
-       if ( $filepath && file_exists($filepath) ) {
-               if ( 'full' != $size && ( $data = image_get_intermediate_size($post_id, $size) ) )
-                       $filepath = path_join( dirname($filepath), $data['file'] );
-       } elseif ( WP_Http_Fopen::test() ) {
-               $filepath = wp_get_attachment_url($post_id);
-       }
+/**
+ * Streams image in WP_Image_Editor to browser.
+ * Provided for backcompat reasons
+ *
+ * @param WP_Image_Editor $image
+ * @param string $mime_type
+ * @param int $post_id
+ * @return boolean
+ */
+function wp_stream_image( $image, $mime_type, $post_id ) {
+       if ( $image instanceof WP_Image_Editor ) {
+               $image = apply_filters('image_editor_save_pre', $image, $post_id);
 
-       $filepath = apply_filters('load_image_to_edit_path', $filepath, $post_id, $size);
-       if ( empty($filepath) )
-               return false;
+               if ( is_wp_error( $image->stream( $mime_type ) ) )
+                       return false;
 
-       switch ( $mime_type ) {
-               case 'image/jpeg':
-                       $image = imagecreatefromjpeg($filepath);
-                       break;
-               case 'image/png':
-                       $image = imagecreatefrompng($filepath);
-                       break;
-               case 'image/gif':
-                       $image = imagecreatefromgif($filepath);
-                       break;
-               default:
-                       $image = false;
-                       break;
-       }
-       if ( is_resource($image) ) {
-               $image = apply_filters('load_image_to_edit', $image, $post_id, $size);
-               if ( function_exists('imagealphablending') && function_exists('imagesavealpha') ) {
-                       imagealphablending($image, false);
-                       imagesavealpha($image, true);
+               return true;
+       } else {
+               _deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
+
+               $image = apply_filters('image_save_pre', $image, $post_id);
+
+               switch ( $mime_type ) {
+                       case 'image/jpeg':
+                               header( 'Content-Type: image/jpeg' );
+                               return imagejpeg( $image, null, 90 );
+                       case 'image/png':
+                               header( 'Content-Type: image/png' );
+                               return imagepng( $image );
+                       case 'image/gif':
+                               header( 'Content-Type: image/gif' );
+                               return imagegif( $image );
+                       default:
+                               return false;
                }
        }
-       return $image;
 }
 
-function wp_stream_image($image, $mime_type, $post_id) {
-       $image = apply_filters('image_save_pre', $image, $post_id);
-
-       switch ( $mime_type ) {
-               case 'image/jpeg':
-                       header('Content-Type: image/jpeg');
-                       return imagejpeg($image, null, 90);
-               case 'image/png':
-                       header('Content-Type: image/png');
-                       return imagepng($image);
-               case 'image/gif':
-                       header('Content-Type: image/gif');
-                       return imagegif($image);
-               default:
-                       return false;
-       }
-}
+/**
+ * Saves Image to File
+ *
+ * @param string $filename
+ * @param WP_Image_Editor $image
+ * @param string $mime_type
+ * @param int $post_id
+ * @return boolean
+ */
+function wp_save_image_file( $filename, $image, $mime_type, $post_id ) {
+       if ( $image instanceof WP_Image_Editor ) {
+               $image = apply_filters('image_editor_save_pre', $image, $post_id);
+               $saved = apply_filters('wp_save_image_editor_file', null, $filename, $image, $mime_type, $post_id);
 
-function wp_save_image_file($filename, $image, $mime_type, $post_id) {
-       $image = apply_filters('image_save_pre', $image, $post_id);
-       $saved = apply_filters('wp_save_image_file', null, $filename, $image, $mime_type, $post_id);
-       if ( null !== $saved )
-               return $saved;
-
-       switch ( $mime_type ) {
-               case 'image/jpeg':
-                       return imagejpeg( $image, $filename, apply_filters( 'jpeg_quality', 90, 'edit_image' ) );
-               case 'image/png':
-                       return imagepng($image, $filename);
-               case 'image/gif':
-                       return imagegif($image, $filename);
-               default:
-                       return false;
+               if ( null !== $saved )
+                       return $saved;
+
+               return $image->save( $filename, $mime_type );
+       } else {
+               _deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
+
+               $image = apply_filters('image_save_pre', $image, $post_id);
+               $saved = apply_filters('wp_save_image_file', null, $filename, $image, $mime_type, $post_id);
+
+               if ( null !== $saved )
+                       return $saved;
+
+               switch ( $mime_type ) {
+                       case 'image/jpeg':
+                               /** This filter is documented in wp-includes/class-wp-image-editor.php */
+                               return imagejpeg( $image, $filename, apply_filters( 'jpeg_quality', 90, 'edit_image' ) );
+                       case 'image/png':
+                               return imagepng( $image, $filename );
+                       case 'image/gif':
+                               return imagegif( $image, $filename );
+                       default:
+                               return false;
+               }
        }
 }
 
@@ -276,7 +276,9 @@ function _image_get_preview_ratio($w, $h) {
        return $max > 400 ? (400 / $max) : 1;
 }
 
+// @TODO: Returns GD resource, but is NOT public
 function _rotate_image_resource($img, $angle) {
+       _deprecated_function( __FUNCTION__, '3.5', __( 'Use WP_Image_Editor::rotate' ) );
        if ( function_exists('imagerotate') ) {
                $rotated = imagerotate($img, $angle, 0);
                if ( is_resource($rotated) ) {
@@ -287,8 +289,18 @@ function _rotate_image_resource($img, $angle) {
        return $img;
 }
 
-
+/**
+ * @TODO: Only used within image_edit_apply_changes
+ *               and receives/returns GD Resource.
+ *               Consider removal.
+ *
+ * @param GD_Resource $img
+ * @param boolean $horz
+ * @param boolean $vert
+ * @return GD_Resource
+ */
 function _flip_image_resource($img, $horz, $vert) {
+       _deprecated_function( __FUNCTION__, '3.5', __( 'Use WP_Image_Editor::flip' ) );
        $w = imagesx($img);
        $h = imagesy($img);
        $dst = wp_imagecreatetruecolor($w, $h);
@@ -306,6 +318,18 @@ function _flip_image_resource($img, $horz, $vert) {
        return $img;
 }
 
+/**
+ * @TODO: Only used within image_edit_apply_changes
+ *               and receives/returns GD Resource.
+ *               Consider removal.
+ *
+ * @param GD_Resource $img
+ * @param float $x
+ * @param float $y
+ * @param float $w
+ * @param float $h
+ * @return GD_Resource
+ */
 function _crop_image_resource($img, $x, $y, $w, $h) {
        $dst = wp_imagecreatetruecolor($w, $h);
        if ( is_resource($dst) ) {
@@ -317,10 +341,19 @@ function _crop_image_resource($img, $x, $y, $w, $h) {
        return $img;
 }
 
-function image_edit_apply_changes($img, $changes) {
+/**
+ * Performs group of changes on Editor specified.
+ *
+ * @param WP_Image_Editor $image
+ * @param type $changes
+ * @return WP_Image_Editor
+ */
+function image_edit_apply_changes( $image, $changes ) {
+       if ( is_resource( $image ) )
+               _deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
 
        if ( !is_array($changes) )
-               return $img;
+               return $image;
 
        // expand change operations
        foreach ( $changes as $key => $obj ) {
@@ -365,55 +398,83 @@ function image_edit_apply_changes($img, $changes) {
        }
 
        // image resource before applying the changes
-       $img = apply_filters('image_edit_before_change', $img, $changes);
+       if ( $image instanceof WP_Image_Editor )
+               $image = apply_filters('wp_image_editor_before_change', $image, $changes);
+       elseif ( is_resource( $image ) )
+               $image = apply_filters('image_edit_before_change', $image, $changes);
 
        foreach ( $changes as $operation ) {
                switch ( $operation->type ) {
                        case 'rotate':
-                               if ( $operation->angle != 0 )
-                                       $img = _rotate_image_resource($img, $operation->angle);
+                               if ( $operation->angle != 0 ) {
+                                       if ( $image instanceof WP_Image_Editor )
+                                               $image->rotate( $operation->angle );
+                                       else
+                                               $image = _rotate_image_resource( $image, $operation->angle );
+                               }
                                break;
                        case 'flip':
                                if ( $operation->axis != 0 )
-                                       $img = _flip_image_resource($img, ($operation->axis & 1) != 0, ($operation->axis & 2) != 0);
+                                       if ( $image instanceof WP_Image_Editor )
+                                               $image->flip( ($operation->axis & 1) != 0, ($operation->axis & 2) != 0 );
+                                       else
+                                               $image = _flip_image_resource( $image, ( $operation->axis & 1 ) != 0, ( $operation->axis & 2 ) != 0 );
                                break;
                        case 'crop':
                                $sel = $operation->sel;
-                               $scale = 1 / _image_get_preview_ratio( imagesx($img), imagesy($img) ); // discard preview scaling
-                               $img = _crop_image_resource($img, $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale);
+
+                               if ( $image instanceof WP_Image_Editor ) {
+                                       $size = $image->get_size();
+                                       $w = $size['width'];
+                                       $h = $size['height'];
+
+                                       $scale = 1 / _image_get_preview_ratio( $w, $h ); // discard preview scaling
+                                       $image->crop( $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
+                               } else {
+                                       $scale = 1 / _image_get_preview_ratio( imagesx( $image ), imagesy( $image ) ); // discard preview scaling
+                                       $image = _crop_image_resource( $image, $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
+                               }
                                break;
                }
        }
 
-       return $img;
+       return $image;
 }
 
-function stream_preview_image($post_id) {
-       $post = get_post($post_id);
-       @ini_set('memory_limit', '256M');
-       $img = load_image_to_edit( $post_id, $post->post_mime_type, array(400, 400) );
 
-       if ( !is_resource($img) )
-               return false;
+/**
+ * Streams image in post to browser, along with enqueued changes
+ * in $_REQUEST['history']
+ *
+ * @param int $post_id
+ * @return boolean
+ */
+function stream_preview_image( $post_id ) {
+       $post = get_post( $post_id );
+       @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
+
+       $img = wp_get_image_editor( _load_image_to_edit_path( $post_id ) );
+
+    if ( is_wp_error( $img ) )
+        return false;
 
-       $changes = !empty($_REQUEST['history']) ? json_decode( stripslashes($_REQUEST['history']) ) : null;
+       $changes = !empty($_REQUEST['history']) ? json_decode( wp_unslash($_REQUEST['history']) ) : null;
        if ( $changes )
-               $img = image_edit_apply_changes($img, $changes);
+               $img = image_edit_apply_changes( $img, $changes );
 
        // scale the image
-       $w = imagesx($img);
-       $h = imagesy($img);
-       $ratio = _image_get_preview_ratio($w, $h);
-       $w2 = $w * $ratio;
-       $h2 = $h * $ratio;
+       $size = $img->get_size();
+       $w = $size['width'];
+       $h = $size['height'];
 
-       $preview = wp_imagecreatetruecolor($w2, $h2);
-       imagecopyresampled( $preview, $img, 0, 0, 0, 0, $w2, $h2, $w, $h );
-       wp_stream_image($preview, $post->post_mime_type, $post_id);
+       $ratio = _image_get_preview_ratio( $w, $h );
+       $w2 = max ( 1, $w * $ratio );
+       $h2 = max ( 1, $h * $ratio );
+
+       if ( is_wp_error( $img->resize( $w2, $h2 ) ) )
+               return false;
 
-       imagedestroy($preview);
-       imagedestroy($img);
-       return true;
+       return wp_stream_image( $img, $post->post_mime_type, $post_id );
 }
 
 function wp_restore_image($post_id) {
@@ -421,7 +482,7 @@ function wp_restore_image($post_id) {
        $file = get_attached_file($post_id);
        $backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
        $restored = false;
-       $msg = '';
+       $msg = new stdClass;
 
        if ( !is_array($backup_sizes) ) {
                $msg->error = __('Cannot load image metadata.');
@@ -430,7 +491,7 @@ function wp_restore_image($post_id) {
 
        $parts = pathinfo($file);
        $suffix = time() . rand(100, 999);
-       $default_sizes = apply_filters( 'intermediate_image_sizes', array('large', 'medium', 'thumbnail') );
+       $default_sizes = get_intermediate_image_sizes();
 
        if ( isset($backup_sizes['full-orig']) && is_array($backup_sizes['full-orig']) ) {
                $data = $backup_sizes['full-orig'];
@@ -439,10 +500,11 @@ function wp_restore_image($post_id) {
                        if ( defined('IMAGE_EDIT_OVERWRITE') && IMAGE_EDIT_OVERWRITE ) {
                                // delete only if it's edited image
                                if ( preg_match('/-e[0-9]{13}\./', $parts['basename']) ) {
+                                       /** This filter is documented in wp-admin/custom-header.php */
                                        $delpath = apply_filters('wp_delete_file', $file);
                                        @unlink($delpath);
                                }
-                       } else {
+                       } elseif ( isset( $meta['width'], $meta['height'] ) ) {
                                $backup_sizes["full-$suffix"] = array('width' => $meta['width'], 'height' => $meta['height'], 'file' => $parts['basename']);
                        }
                }
@@ -453,8 +515,6 @@ function wp_restore_image($post_id) {
                $meta['file'] = _wp_relative_upload_path( $restored_file );
                $meta['width'] = $data['width'];
                $meta['height'] = $data['height'];
-               list ( $uwidth, $uheight ) = wp_constrain_dimensions($meta['width'], $meta['height'], 128, 96);
-               $meta['hwstring_small'] = "height='$uheight' width='$uwidth'";
        }
 
        foreach ( $default_sizes as $default_size ) {
@@ -464,6 +524,7 @@ function wp_restore_image($post_id) {
                                if ( defined('IMAGE_EDIT_OVERWRITE') && IMAGE_EDIT_OVERWRITE ) {
                                        // delete only if it's edited image
                                        if ( preg_match('/-e[0-9]{13}-/', $meta['sizes'][$default_size]['file']) ) {
+                                               /** This filter is documented in wp-admin/custom-header.php */
                                                $delpath = apply_filters( 'wp_delete_file', path_join($parts['dirname'], $meta['sizes'][$default_size]['file']) );
                                                @unlink($delpath);
                                        }
@@ -491,14 +552,20 @@ function wp_restore_image($post_id) {
        return $msg;
 }
 
-function wp_save_image($post_id) {
-       $return = '';
+/**
+ * Saves image to post along with enqueued changes
+ * in $_REQUEST['history']
+ *
+ * @param int $post_id
+ * @return \stdClass
+ */
+function wp_save_image( $post_id ) {
+       $return = new stdClass;
        $success = $delete = $scaled = $nocrop = false;
-       $post = get_post($post_id);
-       @ini_set('memory_limit', '256M');
-       $img = load_image_to_edit($post_id, $post->post_mime_type);
+       $post = get_post( $post_id );
 
-       if ( !is_resource($img) ) {
+       $img = wp_get_image_editor( _load_image_to_edit_path( $post_id, 'full' ) );
+       if ( is_wp_error( $img ) ) {
                $return->error = esc_js( __('Unable to create new image.') );
                return $return;
        }
@@ -509,19 +576,16 @@ function wp_save_image($post_id) {
        $scale = !empty($_REQUEST['do']) && 'scale' == $_REQUEST['do'];
 
        if ( $scale && $fwidth > 0 && $fheight > 0 ) {
-               $sX = imagesx($img);
-               $sY = imagesy($img);
+               $size = $img->get_size();
+               $sX = $size['width'];
+               $sY = $size['height'];
 
                // check if it has roughly the same w / h ratio
                $diff = round($sX / $sY, 2) - round($fwidth / $fheight, 2);
                if ( -0.1 < $diff && $diff < 0.1 ) {
                        // scale the full size image
-                       $dst = wp_imagecreatetruecolor($fwidth, $fheight);
-                       if ( imagecopyresampled( $dst, $img, 0, 0, 0, 0, $fwidth, $fheight, $sX, $sY ) ) {
-                               imagedestroy($img);
-                               $img = $dst;
+                       if ( $img->resize( $fwidth, $fheight ) )
                                $scaled = true;
-                       }
                }
 
                if ( !$scaled ) {
@@ -529,7 +593,7 @@ function wp_save_image($post_id) {
                        return $return;
                }
        } elseif ( !empty($_REQUEST['history']) ) {
-               $changes = json_decode( stripslashes($_REQUEST['history']) );
+               $changes = json_decode( wp_unslash($_REQUEST['history']) );
                if ( $changes )
                        $img = image_edit_apply_changes($img, $changes);
        } else {
@@ -550,7 +614,7 @@ function wp_save_image($post_id) {
 
        // generate new filename
        $path = get_attached_file($post_id);
-       $path_parts = pathinfo52( $path );
+       $path_parts = pathinfo( $path );
        $filename = $path_parts['filename'];
        $suffix = time() . rand(100, 999);
 
@@ -592,17 +656,16 @@ function wp_save_image($post_id) {
                if ( $tag )
                        $backup_sizes[$tag] = array('width' => $meta['width'], 'height' => $meta['height'], 'file' => $path_parts['basename']);
 
-               $success = update_attached_file($post_id, $new_path);
+               $success = update_attached_file( $post_id, $new_path );
 
-               $meta['file'] = _wp_relative_upload_path($new_path);
-               $meta['width'] = imagesx($img);
-               $meta['height'] = imagesy($img);
+               $meta['file'] = _wp_relative_upload_path( $new_path );
 
-               list ( $uwidth, $uheight ) = wp_constrain_dimensions($meta['width'], $meta['height'], 128, 96);
-               $meta['hwstring_small'] = "height='$uheight' width='$uwidth'";
+               $size = $img->get_size();
+               $meta['width'] = $size['width'];
+               $meta['height'] = $size['height'];
 
                if ( $success && ('nothumb' == $target || 'all' == $target) ) {
-                       $sizes = apply_filters( 'intermediate_image_sizes', array('large', 'medium', 'thumbnail') );
+                       $sizes = get_intermediate_image_sizes();
                        if ( 'nothumb' == $target )
                                $sizes = array_diff( $sizes, array('thumbnail') );
                }
@@ -614,10 +677,12 @@ function wp_save_image($post_id) {
                $success = $delete = $nocrop = true;
        }
 
-       if ( isset($sizes) ) {
+       if ( isset( $sizes ) ) {
+               $_sizes = array();
+
                foreach ( $sizes as $size ) {
                        $tag = false;
-                       if ( isset($meta['sizes'][$size]) ) {
+                       if ( isset( $meta['sizes'][$size] ) ) {
                                if ( isset($backup_sizes["$size-orig"]) ) {
                                        if ( ( !defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE ) && $backup_sizes["$size-orig"]['file'] != $meta['sizes'][$size]['file'] )
                                                $tag = "$size-$suffix";
@@ -630,38 +695,41 @@ function wp_save_image($post_id) {
                        }
 
                        $crop = $nocrop ? false : get_option("{$size}_crop");
-                       $resized = image_make_intermediate_size($new_path, get_option("{$size}_size_w"), get_option("{$size}_size_h"), $crop );
-
-                       if ( $resized )
-                               $meta['sizes'][$size] = $resized;
-                       else
-                               unset($meta['sizes'][$size]);
+                       $_sizes[ $size ] = array( 'width' => get_option("{$size}_size_w"), 'height' => get_option("{$size}_size_h"), 'crop' => $crop );
                }
+
+               $meta['sizes'] = array_merge( $meta['sizes'], $img->multi_resize( $_sizes ) );
        }
 
+       unset( $img );
+
        if ( $success ) {
-               wp_update_attachment_metadata($post_id, $meta);
+               wp_update_attachment_metadata( $post_id, $meta );
                update_post_meta( $post_id, '_wp_attachment_backup_sizes', $backup_sizes);
 
                if ( $target == 'thumbnail' || $target == 'all' || $target == 'full' ) {
-                       $file_url = wp_get_attachment_url($post_id);
-                       if ( $thumb = $meta['sizes']['thumbnail'] )
-                               $return->thumbnail = path_join( dirname($file_url), $thumb['file'] );
-                       else
-                               $return->thumbnail = "$file_url?w=128&h=128";
+                       // Check if it's an image edit from attachment edit screen
+                       if ( ! empty( $_REQUEST['context'] ) && 'edit-attachment' == $_REQUEST['context'] ) {
+                               $thumb_url = wp_get_attachment_image_src( $post_id, array( 900, 600 ), true );
+                               $return->thumbnail = $thumb_url[0];
+                       } else {
+                               $file_url = wp_get_attachment_url($post_id);
+                               if ( $thumb = $meta['sizes']['thumbnail'] )
+                                       $return->thumbnail = path_join( dirname($file_url), $thumb['file'] );
+                               else
+                                       $return->thumbnail = "$file_url?w=128&h=128";
+                       }
                }
        } else {
                $delete = true;
        }
 
        if ( $delete ) {
+               /** This filter is documented in wp-admin/custom-header.php */
                $delpath = apply_filters('wp_delete_file', $new_path);
-               @unlink($delpath);
+               @unlink( $delpath );
        }
 
-       imagedestroy($img);
-
        $return->msg = esc_js( __('Image saved') );
        return $return;
 }
-