diff --git wp-admin/includes/media.php wp-admin/includes/media.php
index 6cc1b63..185b096 100644
--- wp-admin/includes/media.php
+++ wp-admin/includes/media.php
@@ -1122,7 +1122,7 @@ function get_media_item( $attachment_id, $args = null ) {
 	$media_dims = apply_filters( 'media_meta', $media_dims, $post );
 
 	$image_edit_button = '';
-	if ( gd_edit_image_support( $post->post_mime_type ) ) {
+	if ( WP_Image_Editor::supports( array( 'mime_type' => $post->post_mime_type ) ) ) {
 		$nonce = wp_create_nonce( "image_editor-$post->ID" );
 		$image_edit_button = "<input type='button' id='imgedit-open-btn-$post->ID' onclick='imageEdit.open( $post->ID, \"$nonce\" )' class='button' value='" . esc_attr__( 'Edit Image' ) . "' /> <span class='spinner'></span>";
 	}
@@ -2254,7 +2254,7 @@ function edit_form_image_editor() {
 	$att_url = wp_get_attachment_url( $post->ID );
 
 	$image_edit_button = '';
-	if ( gd_edit_image_support( $post->post_mime_type ) ) {
+	if ( WP_Image_Editor::supports( array( 'mime_type' => $post->post_mime_type ) ) ) {
 		$nonce = wp_create_nonce( "image_editor-$post->ID" );
 		$image_edit_button = "<input type='button' id='imgedit-open-btn-$post->ID' onclick='imageEdit.open( $post->ID, \"$nonce\" )' class='button' value='" . esc_attr__( 'Edit Image' ) . "' /> <span class='spinner'></span>";
 	}
diff --git wp-includes/class-wp-image-editor-base.php wp-includes/class-wp-image-editor-base.php
new file mode 100644
index 0000000..b2219a8
--- /dev/null
+++ wp-includes/class-wp-image-editor-base.php
@@ -0,0 +1,394 @@
+<?php
+/**
+ * Base image editor class from which implementations extend
+ *
+ * @since 3.5.0
+ */
+abstract class WP_Image_Editor_Base {
+
+	protected $file = null;
+	protected $size = null;
+	protected $mime_type = null;
+	protected $default_mime_type = 'image/jpeg';
+	protected $quality = 90;
+
+	/**
+	 * Checks to see if current environment supports the editor chosen.
+	 * Must be overridden in a sub-class.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 * @abstract
+	 *
+	 * @param array $args
+	 * @return boolean
+	 */
+	public static function test() {
+		return false;
+	}
+
+	/**
+	 * Checks to see if editor supports the mime-type specified.
+	 * Must be overridden in a sub-class.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 * @abstract
+	 *
+	 * @param string $mime_type
+	 * @return boolean
+	 */
+	public static function supports_mime_type( $mime_type ) {
+		return false;
+	}
+
+	/**
+	 * Each instance handles a single file.
+	 */
+	public function __construct( $file ) {
+		$this->file = $file;
+	}
+
+	/**
+	 * Loads image from $this->file into editor.
+	 *
+	 * @since 3.5.0
+	 * @access protected
+	 * @abstract
+	 *
+	 * @return boolean|WP_Error True if loaded; WP_Error on failure.
+	 */
+	abstract public function load();
+
+	/**
+	 * Saves current image to file.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 * @abstract
+	 *
+	 * @param string $destfilename
+	 * @param string $mime_type
+	 * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
+	 */
+	abstract public function save( $destfilename = null, $mime_type = null );
+
+	/**
+	 * Resizes current image.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 * @abstract
+	 *
+	 * @param int $max_w
+	 * @param int $max_h
+	 * @param boolean $crop
+	 * @return boolean|WP_Error
+	 */
+	abstract public function resize( $max_w, $max_h, $crop = false );
+
+	/**
+	 * Processes current image and saves to disk
+	 * multiple sizes from single source.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 * @abstract
+	 *
+	 * @param array $sizes
+	 * @return array
+	 */
+	abstract public function multi_resize( $sizes );
+
+	/**
+	 * Crops Image.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 * @abstract
+	 *
+	 * @param string|int $src The source file or Attachment ID.
+	 * @param int $src_x The start x position to crop from.
+	 * @param int $src_y The start y position to crop from.
+	 * @param int $src_w The width to crop.
+	 * @param int $src_h The height to crop.
+	 * @param int $dst_w Optional. The destination width.
+	 * @param int $dst_h Optional. The destination height.
+	 * @param boolean $src_abs Optional. If the source crop points are absolute.
+	 * @return boolean|WP_Error
+	 */
+	abstract public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false );
+
+	/**
+	 * Rotates current image counter-clockwise by $angle.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 * @abstract
+	 *
+	 * @param float $angle
+	 * @return boolean|WP_Error
+	 */
+	abstract public function rotate( $angle );
+
+	/**
+	 * Flips current image.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 * @abstract
+	 *
+	 * @param boolean $horz Horizontal Flip
+	 * @param boolean $vert Vertical Flip
+	 * @return boolean|WP_Error
+	 */
+	abstract public function flip( $horz, $vert );
+
+	/**
+	 * Streams current image to browser.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 * @abstract
+	 *
+	 * @param string $mime_type
+	 * @return boolean|WP_Error
+	 */
+	abstract public function stream( $mime_type = null );
+
+	/**
+	 * Gets dimensions of image.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 *
+	 * @return array {'width'=>int, 'height'=>int}
+	 */
+	public function get_size() {
+		return $this->size;
+	}
+
+	/**
+	 * Sets current image size.
+	 *
+	 * @since 3.5.0
+	 * @access protected
+	 *
+	 * @param int $width
+	 * @param int $height
+	 */
+	protected function update_size( $width = null, $height = null ) {
+		$this->size = array(
+			'width' => $width,
+			'height' => $height
+		);
+		return true;
+	}
+
+	/**
+	 * Sets Image Compression quality on a 1-100% scale.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 *
+	 * @param int $quality Compression Quality. Range: [1,100]
+	 * @return boolean
+	 */
+	public function set_quality( $quality ) {
+		$this->quality = apply_filters( 'wp_editor_set_quality', $quality );
+
+		return ( (bool) $this->quality );
+	}
+
+	/**
+	 * Returns preferred mime-type and extension based on provided
+	 * file's extension and mime, or current file's extension and mime.
+	 *
+	 * Will default to $this->default_mime_type if requested is not supported.
+	 *
+	 * Provides corrected filename only if filename is provided.
+	 *
+	 * @since 3.5.0
+	 * @access protected
+	 *
+	 * @param string $filename
+	 * @param string $mime_type
+	 * @return array { filename|null, extension, mime-type }
+	 */
+	protected function get_output_format( $filename = null, $mime_type = null ) {
+		$new_ext = $file_ext = null;
+		$file_mime = null;
+
+		// By default, assume specified type takes priority
+		if ( $mime_type ) {
+			$new_ext = $this->get_extension( $mime_type );
+		}
+
+		if ( $filename ) {
+			$file_ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
+			$file_mime = $this->get_mime_type( $file_ext );
+		}
+		else {
+			// If no file specified, grab editor's current extension and mime-type.
+			$file_ext = strtolower( pathinfo( $this->file, PATHINFO_EXTENSION ) );
+			$file_mime = $this->mime_type;
+		}
+
+		// Check to see if specified mime-type is the same as type implied by
+		// file extension.  If so, prefer extension from file.
+		if ( ! $mime_type || ( $file_mime == $mime_type ) ) {
+			$mime_type = $file_mime;
+			$new_ext = $file_ext;
+		}
+
+		// Double-check that the mime-type selected is supported by the editor.
+		// If not, choose a default instead.
+		if ( ! $this->supports_mime_type( $mime_type ) ) {
+			$mime_type = apply_filters( 'image_editor_default_mime_type', $this->default_mime_type );
+			$new_ext = $this->get_extension( $mime_type );
+		}
+
+		if ( $filename ) {
+			$ext = '';
+			$info = pathinfo( $filename );
+			$dir  = $info['dirname'];
+
+			if( isset( $info['extension'] ) )
+				$ext = $info['extension'];
+
+			$filename = trailingslashit( $dir ) . wp_basename( $filename, ".$ext" ) . ".{$new_ext}";
+		}
+
+		return array( $filename, $new_ext, $mime_type );
+	}
+
+	/**
+	 * Builds an output filename based on current file, and adding proper suffix
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 *
+	 * @param string $suffix
+	 * @param string $dest_path
+	 * @param string $extension
+	 * @return string filename
+	 */
+	public function generate_filename( $suffix = null, $dest_path = null, $extension = null ) {
+		// $suffix will be appended to the destination filename, just before the extension
+		if ( ! $suffix )
+			$suffix = $this->get_suffix();
+
+		$info = pathinfo( $this->file );
+		$dir  = $info['dirname'];
+		$ext  = $info['extension'];
+
+		$name = wp_basename( $this->file, ".$ext" );
+		$new_ext = strtolower( $extension ? $extension : $ext );
+
+		if ( ! is_null( $dest_path ) && $_dest_path = realpath( $dest_path ) )
+			$dir = $_dest_path;
+
+		return trailingslashit( $dir ) . "{$name}-{$suffix}.{$new_ext}";
+	}
+
+	/**
+	 * Builds and returns proper suffix for file based on height and width.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 *
+	 * @return string suffix
+	 */
+	public function get_suffix() {
+		if ( ! $this->get_size() )
+			return false;
+
+		return "{$this->size['width']}x{$this->size['height']}";
+	}
+
+	/**
+	 * Either calls editor's save function or handles file as a stream.
+	 *
+	 * @since 3.5.0
+	 * @access protected
+	 *
+	 * @param string|stream $filename
+	 * @param callable $function
+	 * @param array $arguments
+	 * @return boolean
+	 */
+	protected function make_image( $filename, $function, $arguments ) {
+		$dst_file = $filename;
+
+		if ( $stream = wp_is_stream( $filename ) ) {
+			$filename = null;
+			ob_start();
+		}
+
+		$result = call_user_func_array( $function, $arguments );
+
+		if ( $result && $stream ) {
+			$contents = ob_get_contents();
+
+			$fp = fopen( $dst_file, 'w' );
+
+			if ( ! $fp )
+				return false;
+
+			fwrite( $fp, $contents );
+			fclose( $fp );
+		}
+
+		if ( $stream ) {
+			ob_end_clean();
+		}
+
+		return $result;
+	}
+
+	/**
+	 * Returns first matched mime-type from extension,
+	 * as mapped from wp_get_mime_types()
+	 *
+	 * @since 3.5.0
+	 * @access protected
+	 *
+	 * @param string $extension
+	 * @return string|boolean
+	 */
+	protected static function get_mime_type( $extension = null ) {
+		if ( ! $extension )
+			return false;
+
+		$mime_types = wp_get_mime_types();
+		$extensions = array_keys( $mime_types );
+
+		foreach( $extensions as $_extension ) {
+			if ( preg_match( "/{$extension}/i", $_extension ) ) {
+				return $mime_types[$_extension];
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns first matched extension from Mime-type,
+	 * as mapped from wp_get_mime_types()
+	 *
+	 * @since 3.5.0
+	 * @access protected
+	 *
+	 * @param string $mime_type
+	 * @return string|boolean
+	 */
+	protected static function get_extension( $mime_type = null ) {
+		$extensions = explode( '|', array_search( $mime_type, wp_get_mime_types() ) );
+
+		if ( empty( $extensions[0] ) )
+			return false;
+
+		return $extensions[0];
+	}
+}
+
diff --git wp-includes/class-wp-image-editor-gd.php wp-includes/class-wp-image-editor-gd.php
index ca76006..411e18f 100644
--- wp-includes/class-wp-image-editor-gd.php
+++ wp-includes/class-wp-image-editor-gd.php
@@ -14,7 +14,8 @@
  * @subpackage Image_Editor
  * @uses WP_Image_Editor Extends class
  */
-class WP_Image_Editor_GD extends WP_Image_Editor {
+class WP_Image_Editor_GD extends WP_Image_Editor_Base {
+
 	protected $image = false; // GD Resource
 
 	function __destruct() {
@@ -32,7 +33,7 @@ class WP_Image_Editor_GD extends WP_Image_Editor {
 	 *
 	 * @return boolean
 	 */
-	public static function test( $args = null ) {
+	public static function test() {
 		if ( ! extension_loaded('gd') || ! function_exists('gd_info') )
 			return false;
 
@@ -40,6 +41,29 @@ class WP_Image_Editor_GD extends WP_Image_Editor {
 	}
 
 	/**
+	 * Checks to see if editor supports the mime-type specified.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 *
+	 * @param string $mime_type
+	 * @return boolean
+	 */
+	public static function supports_mime_type( $mime_type ) {
+		$image_types = imagetypes();
+		switch( $mime_type ) {
+			case 'image/jpeg':
+				return ($image_types & IMG_JPG) != 0;
+			case 'image/png':
+				return ($image_types & IMG_PNG) != 0;
+			case 'image/gif':
+				return ($image_types & IMG_GIF) != 0;
+		}
+
+		return false;
+	}
+
+	/**
 	 * Loads image from $this->file into new GD Resource.
 	 *
 	 * @since 3.5.0
@@ -47,7 +71,7 @@ class WP_Image_Editor_GD extends WP_Image_Editor {
 	 *
 	 * @return boolean|\WP_Error
 	 */
-	protected function load() {
+	public function load() {
 		if ( $this->image )
 			return true;
 
@@ -91,21 +115,6 @@ class WP_Image_Editor_GD extends WP_Image_Editor {
 	}
 
 	/**
-	 * Checks to see if editor supports the mime-type specified.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 *
-	 * @param string $mime_type
-	 * @return boolean
-	 */
-	public static function supports_mime_type( $mime_type ) {
-		$allowed_mime_types = array( 'image/gif', 'image/png', 'image/jpeg' );
-
-		return in_array( $mime_type, $allowed_mime_types );
-	}
-
-	/**
 	 * Resizes current image.
 	 * Wraps _resize, since _resize returns a GD Resource.
 	 *
@@ -261,7 +270,7 @@ class WP_Image_Editor_GD extends WP_Image_Editor {
 	 * @since 3.5.0
 	 * @access public
 	 *
-	 * @param boolean $horz Horizonal Flip
+	 * @param boolean $horz Horizontal Flip
 	 * @param boolean $vert Vertical Flip
 	 * @returns boolean|WP_Error
 	 */
@@ -369,4 +378,4 @@ class WP_Image_Editor_GD extends WP_Image_Editor {
 				return imagejpeg( $this->image, null, $this->quality );
 		}
 	}
-}
\ No newline at end of file
+}
diff --git wp-includes/class-wp-image-editor-imagick.php wp-includes/class-wp-image-editor-imagick.php
index 601b99b..5fccaee 100644
--- wp-includes/class-wp-image-editor-imagick.php
+++ wp-includes/class-wp-image-editor-imagick.php
@@ -14,7 +14,8 @@
  * @subpackage Image_Editor
  * @uses WP_Image_Editor Extends class
  */
-class WP_Image_Editor_Imagick extends WP_Image_Editor {
+class WP_Image_Editor_Imagick extends WP_Image_Editor_Base {
+
 	protected $image = null; // Imagick Object
 
 	function __destruct() {
@@ -36,7 +37,7 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor {
 	 *
 	 * @return boolean
 	 */
-	public static function test( $args = null ) {
+	public static function test() {
 		if ( ! extension_loaded( 'imagick' ) || ! is_callable( 'Imagick', 'queryFormats' ) )
 			return false;
 
@@ -44,6 +45,29 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor {
 	}
 
 	/**
+	 * Checks to see if editor supports the mime-type specified.
+	 *
+	 * @since 3.5.0
+	 * @access public
+	 *
+	 * @param string $mime_type
+	 * @return boolean
+	 */
+	public static function supports_mime_type( $mime_type ) {
+		$imagick_extension = strtoupper( self::get_extension( $mime_type ) );
+
+		if ( ! $imagick_extension )
+			return false;
+
+		try {
+			return ( (bool) Imagick::queryFormats( $imagick_extension ) );
+		}
+		catch ( Exception $e ) {
+			return false;
+		}
+	}
+
+	/**
 	 * Loads image from $this->file into new Imagick Object.
 	 *
 	 * @since 3.5.0
@@ -51,7 +75,7 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor {
 	 *
 	 * @return boolean|WP_Error True if loaded; WP_Error on failure.
 	 */
-	protected function load() {
+	public function load() {
 		if ( $this->image )
 			return true;
 
@@ -138,29 +162,6 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor {
 	}
 
 	/**
-	 * Checks to see if editor supports the mime-type specified.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 *
-	 * @param string $mime_type
-	 * @return boolean
-	 */
-	public static function supports_mime_type( $mime_type ) {
-		if ( ! $mime_type )
-			return false;
-
-		$imagick_extension = strtoupper( self::get_extension( $mime_type ) );
-
-		try {
-			return ( (bool) Imagick::queryFormats( $imagick_extension ) );
-		}
-		catch ( Exception $e ) {
-			return false;
-		}
-	}
-
-	/**
 	 * Resizes current image.
 	 *
 	 * @since 3.5.0
@@ -312,7 +313,7 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor {
 	 * @since 3.5.0
 	 * @access public
 	 *
-	 * @param boolean $horz Horizonal Flip
+	 * @param boolean $horz Horizontal Flip
 	 * @param boolean $vert Vertical Flip
 	 * @returns boolean|WP_Error
 	 */
diff --git wp-includes/class-wp-image-editor.php wp-includes/class-wp-image-editor.php
index 920e4a4..391c8e1 100644
--- wp-includes/class-wp-image-editor.php
+++ wp-includes/class-wp-image-editor.php
@@ -1,26 +1,10 @@
 <?php
 /**
- * Base WordPress Image Editor
- *
- * @package WordPress
- * @subpackage Image_Editor
- */
-
-/**
- * Base WordPress Image Editor class for which Editor implementations extend
+ * Class for choosing image editor implementations
  *
  * @since 3.5.0
  */
-abstract class WP_Image_Editor {
-	protected $file = null;
-	protected $size = null;
-	protected $mime_type  = null;
-	protected $default_mime_type = 'image/jpeg';
-	protected $quality = 90;
-
-	protected function __construct( $filename ) {
-		$this->file = $filename;
-	}
+class WP_Image_Editor {
 
 	/**
 	 * Returns a WP_Image_Editor instance and loads file into it.
@@ -28,12 +12,21 @@ abstract class WP_Image_Editor {
 	 * @since 3.5.0
 	 * @access public
 	 *
-	 * @param string $path Path to File to Load
-	 * @param array $required_methods Methods to require in implementation
+	 * @param string $path Path to file to load
+	 * @param array $args Additional data. Accepts { 'mime_type'=>string, 'methods'=>{string, string, ...} }
 	 * @return WP_Image_Editor|WP_Error
 	 */
-	public final static function get_instance( $path = null, $required_methods = null ) {
-		$implementation = apply_filters( 'wp_image_editor_class', self::choose_implementation( $required_methods ), $path );
+	public final static function get_instance( $path, $args = array() ) {
+		if ( ! isset( $args['mime_type'] ) ) {
+			$file_info  = wp_check_filetype( $path );
+
+			// If $file_info['type'] is false, then we let the editor attempt to
+			// figure out the file type, rather than forcing a failure based on extension.
+			if ( isset( $file_info ) && $file_info['type'] )
+				$args['mime_type'] = $file_info['type'];
+		}
+
+		$implementation = apply_filters( 'wp_image_editor_class', self::choose_implementation( $args ) );
 
 		if ( $implementation ) {
 			$editor = new $implementation( $path );
@@ -45,409 +38,55 @@ abstract class WP_Image_Editor {
 			return $editor;
 		}
 
-		return new WP_Error( 'no_editor', __('No editor could be selected') );
-	}
-
-	/**
-	 * Tests which editors are capable of supporting the request.
-	 *
-	 * @since 3.5.0
-	 * @access private
-	 *
-	 * @param array $required_methods String array of all methods required for implementation returned.
-	 * @return string|bool Class name for the first editor that claims to support the request. False if no editor claims to support the request.
-	 */
-	private final static function choose_implementation( $required_methods = null ) {
-		$request_order = apply_filters( 'wp_image_editors',
-			array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) );
-
-		if ( ! $required_methods )
-			$required_methods = array();
-
-		// Loop over each editor on each request looking for one which will serve this request's needs
-		foreach ( $request_order as $editor ) {
-			// Check to see if this editor is a possibility, calls the editor statically
-			if ( ! call_user_func( array( $editor, 'test' ) ) )
-				continue;
-
-			// Make sure that all methods are supported by editor.
-			if ( array_diff( $required_methods, get_class_methods( $editor ) ) )
-				continue;
-
-			return $editor;
-		}
-		return false;
-	}
-
-	/**
-	 * Loads image from $this->file into editor.
-	 *
-	 * @since 3.5.0
-	 * @access protected
-	 * @abstract
-	 *
-	 * @return boolean|WP_Error True if loaded; WP_Error on failure.
-	 */
-	abstract protected function load();
-
-	/**
-	 * Saves current image to file.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 * @abstract
-	 *
-	 * @param string $destfilename
-	 * @param string $mime_type
-	 * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
-	 */
-	abstract public function save( $destfilename = null, $mime_type = null );
-
-	/**
-	 * Resizes current image.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 * @abstract
-	 *
-	 * @param int $max_w
-	 * @param int $max_h
-	 * @param boolean $crop
-	 * @return boolean|WP_Error
-	 */
-	abstract public function resize( $max_w, $max_h, $crop = false );
-
-	/**
-	 * Processes current image and saves to disk
-	 * multiple sizes from single source.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 * @abstract
-	 *
-	 * @param array $sizes
-	 * @return array
-	 */
-	abstract public function multi_resize( $sizes );
-
-	/**
-	 * Crops Image.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 * @abstract
-	 *
-	 * @param string|int $src The source file or Attachment ID.
-	 * @param int $src_x The start x position to crop from.
-	 * @param int $src_y The start y position to crop from.
-	 * @param int $src_w The width to crop.
-	 * @param int $src_h The height to crop.
-	 * @param int $dst_w Optional. The destination width.
-	 * @param int $dst_h Optional. The destination height.
-	 * @param boolean $src_abs Optional. If the source crop points are absolute.
-	 * @return boolean|WP_Error
-	 */
-	abstract public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false );
-
-	/**
-	 * Rotates current image counter-clockwise by $angle.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 * @abstract
-	 *
-	 * @param float $angle
-	 * @return boolean|WP_Error
-	 */
-	abstract public function rotate( $angle );
-
-	/**
-	 * Flips current image.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 * @abstract
-	 *
-	 * @param boolean $horz Horizonal Flip
-	 * @param boolean $vert Vertical Flip
-	 * @return boolean|WP_Error
-	 */
-	abstract public function flip( $horz, $vert );
-
-	/**
-	 * Streams current image to browser.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 * @abstract
-	 *
-	 * @param string $mime_type
-	 * @return boolean|WP_Error
-	 */
-	abstract public function stream( $mime_type = null );
-
-	/**
-	 * Checks to see if current environment supports the editor chosen.
-	 * Must be overridden in a sub-class.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 * @abstract
-	 *
-	 * @param array $args
-	 * @return boolean
-	 */
-	public static function test( $args = null ) {
-		return false;
-	}
-
-	/**
-	 * Checks to see if editor supports the mime-type specified.
-	 * Must be overridden in a sub-class.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 * @abstract
-	 *
-	 * @param string $mime_type
-	 * @return boolean
-	 */
-	public static function supports_mime_type( $mime_type ) {
-		return false;
-	}
-
-	/**
-	 * Gets dimensions of image.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 *
-	 * @return array {'width'=>int, 'height'=>int}
-	 */
-	public function get_size() {
-		return $this->size;
-	}
-
-	/**
-	 * Sets current image size.
-	 *
-	 * @since 3.5.0
-	 * @access protected
-	 *
-	 * @param int $width
-	 * @param int $height
-	 */
-	protected function update_size( $width = null, $height = null ) {
-		$this->size = array(
-			'width' => $width,
-			'height' => $height
-		);
-		return true;
-	}
-
-	/**
-	 * Sets Image Compression quality on a 1-100% scale.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 *
-	 * @param int $quality Compression Quality. Range: [1,100]
-	 * @return boolean
-	 */
-	public function set_quality( $quality ) {
-		$this->quality = apply_filters( 'wp_editor_set_quality', $quality );
-
-		return ( (bool) $this->quality );
-	}
-
-	/**
-	 * Returns preferred mime-type and extension based on provided
-	 * file's extension and mime, or current file's extension and mime.
-	 *
-	 * Will default to $this->default_mime_type if requested is not supported.
-	 *
-	 * Provides corrected filename only if filename is provided.
-	 *
-	 * @since 3.5.0
-	 * @access protected
-	 *
-	 * @param string $filename
-	 * @param string $mime_type
-	 * @return array { filename|null, extension, mime-type }
-	 */
-	protected function get_output_format( $filename = null, $mime_type = null ) {
-		$new_ext = $file_ext = null;
-		$file_mime = null;
-
-		// By default, assume specified type takes priority
-		if ( $mime_type ) {
-			$new_ext = $this->get_extension( $mime_type );
-		}
-
-		if ( $filename ) {
-			$file_ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
-			$file_mime = $this->get_mime_type( $file_ext );
-		}
-		else {
-			// If no file specified, grab editor's current extension and mime-type.
-			$file_ext = strtolower( pathinfo( $this->file, PATHINFO_EXTENSION ) );
-			$file_mime = $this->mime_type;
-		}
-
-		// Check to see if specified mime-type is the same as type implied by
-		// file extension.  If so, prefer extension from file.
-		if ( ! $mime_type || ( $file_mime == $mime_type ) ) {
-			$mime_type = $file_mime;
-			$new_ext = $file_ext;
-		}
-
-		// Double-check that the mime-type selected is supported by the editor.
-		// If not, choose a default instead.
-		if ( ! $this->supports_mime_type( $mime_type ) ) {
-			$mime_type = apply_filters( 'image_editor_default_mime_type', $this->default_mime_type );
-			$new_ext = $this->get_extension( $mime_type );
-		}
-
-		if ( $filename ) {
-			$ext = '';
-			$info = pathinfo( $filename );
-			$dir  = $info['dirname'];
-
-			if( isset( $info['extension'] ) )
-				$ext = $info['extension'];
-
-			$filename = trailingslashit( $dir ) . wp_basename( $filename, ".$ext" ) . ".{$new_ext}";
-		}
-
-		return array( $filename, $new_ext, $mime_type );
+		return new WP_Error( 'image_no_editor', __('No editor could be selected.') );
 	}
 
 	/**
-	 * Builds an output filename based on current file, and adding proper suffix
+	 * Tests whether there is an editor that supports a given mime type or methods.
 	 *
 	 * @since 3.5.0
 	 * @access public
 	 *
-	 * @param string $suffix
-	 * @param string $dest_path
-	 * @param string $extension
-	 * @return string filename
+	 * @param string|array $args String path to image to check for support, or array of arguments.  Accepts { 'path'=>string, 'mime_type'=>string, 'methods'=>{string, string, ...} }
+	 * @return boolean true if an eligible editor is found; false otherwise
 	 */
-	public function generate_filename( $suffix = null, $dest_path = null, $extension = null ) {
-		// $suffix will be appended to the destination filename, just before the extension
-		if ( ! $suffix )
-			$suffix = $this->get_suffix();
-
-		$info = pathinfo( $this->file );
-		$dir  = $info['dirname'];
-		$ext  = $info['extension'];
-
-		$name = wp_basename( $this->file, ".$ext" );
-		$new_ext = strtolower( $extension ? $extension : $ext );
-
-		if ( ! is_null( $dest_path ) && $_dest_path = realpath( $dest_path ) )
-			$dir = $_dest_path;
-
-		return trailingslashit( $dir ) . "{$name}-{$suffix}.{$new_ext}";
-	}
-
-	/**
-	 * Builds and returns proper suffix for file based on height and width.
-	 *
-	 * @since 3.5.0
-	 * @access public
-	 *
-	 * @return string suffix
-	 */
-	public function get_suffix() {
-		if ( ! $this->get_size() )
-			return false;
-
-		return "{$this->size['width']}x{$this->size['height']}";
+	public static function supports( $args = array() ) {
+		return (bool) self::choose_implementation( $args );
 	}
 
 	/**
-	 * Either calls editor's save function or handles file as a stream.
+	 * Tests which editors are capable of supporting the request.
 	 *
 	 * @since 3.5.0
-	 * @access protected
+	 * @access private
 	 *
-	 * @param string|stream $filename
-	 * @param callable $function
-	 * @param array $arguments
-	 * @return boolean
+	 * @param array $args Additional data. Accepts { 'mime_type'=>string, 'methods'=>{string, string, ...} }
+	 * @return string|bool Class name for the first editor that claims to support the request. False if no editor claims to support the request.
 	 */
-	protected function make_image( $filename, $function, $arguments ) {
-		$dst_file = $filename;
-
-		if ( $stream = wp_is_stream( $filename ) ) {
-			$filename = null;
-			ob_start();
-		}
-
-		$result = call_user_func_array( $function, $arguments );
-
-		if ( $result && $stream ) {
-			$contents = ob_get_contents();
-
-			$fp = fopen( $dst_file, 'w' );
-
-			if ( ! $fp )
-				return false;
-
-			fwrite( $fp, $contents );
-			fclose( $fp );
-		}
-
-		if ( $stream ) {
-			ob_end_clean();
-		}
-
-		return $result;
-	}
+	private static function choose_implementation( $args = array() ) {
+		$implementations = apply_filters( 'wp_image_editors',
+			array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) );
 
-	/**
-	 * Returns first matched mime-type from extension,
-	 * as mapped from wp_get_mime_types()
-	 *
-	 * @since 3.5.0
-	 * @access protected
-	 *
-	 * @param string $extension
-	 * @return string|boolean
-	 */
-	protected static function get_mime_type( $extension = null ) {
-		if ( ! $extension )
-			return false;
+		foreach ( $implementations as $implementation ) {
+			if ( ! call_user_func( array( $implementation, 'test' ), $args ) )
+				continue;
 
-		$mime_types = wp_get_mime_types();
-		$extensions = array_keys( $mime_types );
+			if ( isset( $args['mime_type'] ) &&
+				! call_user_func(
+					array( $implementation, 'supports_mime_type' ),
+					$args['mime_type'] ) ) {
+				continue;
+			}
 
-		foreach( $extensions as $_extension ) {
-			if ( preg_match( "/{$extension}/i", $_extension ) ) {
-				return $mime_types[$_extension];
+			if ( isset( $args['methods'] ) &&
+				 array_diff( $args['methods'], get_class_methods( $implementation ) ) ) {
+				continue;
 			}
+
+			return $implementation;
 		}
 
 		return false;
 	}
-
-	/**
-	 * Returns first matched extension from Mime-type,
-	 * as mapped from wp_get_mime_types()
-	 *
-	 * @since 3.5.0
-	 * @access protected
-	 *
-	 * @param string $mime_type
-	 * @return string|boolean
-	 */
-	protected static function get_extension( $mime_type = null ) {
-		$extensions = explode( '|', array_search( $mime_type, wp_get_mime_types() ) );
-
-		if ( empty( $extensions[0] ) )
-			return false;
-
-		return $extensions[0];
-	}
 }
+
diff --git wp-includes/deprecated.php wp-includes/deprecated.php
index 9e99614..5b841df 100644
--- wp-includes/deprecated.php
+++ wp-includes/deprecated.php
@@ -3328,4 +3328,38 @@ function user_pass_ok($user_login, $user_pass) {
  * @since 2.3.0
  * @deprecated 3.5.0
  */
-function _save_post_hook() {}
\ No newline at end of file
+function _save_post_hook() {}
+
+/**
+ * Check if the installed version of GD supports particular image type
+ *
+ * @since 2.9.0
+ * @deprecated 3.5.0
+ * @see WP_Image_Editor::supports()
+ *
+ * @param string $mime_type
+ * @return bool
+ */
+function gd_edit_image_support($mime_type) {
+	_deprecated_function( __FUNCTION__, '3.5', 'WP_Image_Editor::supports()' );
+	if ( function_exists('imagetypes') ) {
+		switch( $mime_type ) {
+			case 'image/jpeg':
+				return (imagetypes() & IMG_JPG) != 0;
+			case 'image/png':
+				return (imagetypes() & IMG_PNG) != 0;
+			case 'image/gif':
+				return (imagetypes() & IMG_GIF) != 0;
+		}
+	} else {
+		switch( $mime_type ) {
+			case 'image/jpeg':
+				return function_exists('imagecreatefromjpeg');
+			case 'image/png':
+				return function_exists('imagecreatefrompng');
+			case 'image/gif':
+				return function_exists('imagecreatefromgif');
+		}
+	}
+	return false;
+}
\ No newline at end of file
diff --git wp-includes/media.php wp-includes/media.php
index d8475f1..cfc7172 100644
--- wp-includes/media.php
+++ wp-includes/media.php
@@ -904,37 +904,6 @@ function get_taxonomies_for_attachments( $output = 'names' ) {
 }
 
 /**
- * Check if the installed version of GD supports particular image type
- *
- * @since 2.9.0
- *
- * @param string $mime_type
- * @return bool
- */
-function gd_edit_image_support($mime_type) {
-	if ( function_exists('imagetypes') ) {
-		switch( $mime_type ) {
-			case 'image/jpeg':
-				return (imagetypes() & IMG_JPG) != 0;
-			case 'image/png':
-				return (imagetypes() & IMG_PNG) != 0;
-			case 'image/gif':
-				return (imagetypes() & IMG_GIF) != 0;
-		}
-	} else {
-		switch( $mime_type ) {
-			case 'image/jpeg':
-				return function_exists('imagecreatefromjpeg');
-			case 'image/png':
-				return function_exists('imagecreatefrompng');
-			case 'image/gif':
-				return function_exists('imagecreatefromgif');
-		}
-	}
-	return false;
-}
-
-/**
  * Create new GD image resource with transparency support
  * @TODO: Deprecate if possible.
  *
diff --git wp-settings.php wp-settings.php
index ac331c2..bb15067 100644
--- wp-settings.php
+++ wp-settings.php
@@ -144,6 +144,7 @@ require( ABSPATH . WPINC . '/nav-menu-template.php' );
 require( ABSPATH . WPINC . '/admin-bar.php' );
 
 require( ABSPATH . WPINC . '/class-wp-image-editor.php' );
+require( ABSPATH . WPINC . '/class-wp-image-editor-base.php' );
 require( ABSPATH . WPINC . '/class-wp-image-editor-gd.php' );
 require( ABSPATH . WPINC . '/class-wp-image-editor-imagick.php' );
 
