wp/wp-includes/class-wp-image-editor.php
changeset 0 d970ebf37754
child 5 5e2f62d02dcd
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     1 <?php
       
     2 /**
       
     3  * Base WordPress Image Editor
       
     4  *
       
     5  * @package WordPress
       
     6  * @subpackage Image_Editor
       
     7  */
       
     8 
       
     9 /**
       
    10  * Base image editor class from which implementations extend
       
    11  *
       
    12  * @since 3.5.0
       
    13  */
       
    14 abstract class WP_Image_Editor {
       
    15 	protected $file = null;
       
    16 	protected $size = null;
       
    17 	protected $mime_type = null;
       
    18 	protected $default_mime_type = 'image/jpeg';
       
    19 	protected $quality = 90;
       
    20 
       
    21 	/**
       
    22 	 * Each instance handles a single file.
       
    23 	 */
       
    24 	public function __construct( $file ) {
       
    25 		$this->file = $file;
       
    26 	}
       
    27 
       
    28 	/**
       
    29 	 * Checks to see if current environment supports the editor chosen.
       
    30 	 * Must be overridden in a sub-class.
       
    31 	 *
       
    32 	 * @since 3.5.0
       
    33 	 * @access public
       
    34 	 * @abstract
       
    35 	 *
       
    36 	 * @param array $args
       
    37 	 * @return boolean
       
    38 	 */
       
    39 	public static function test( $args = array() ) {
       
    40 		return false;
       
    41 	}
       
    42 
       
    43 	/**
       
    44 	 * Checks to see if editor supports the mime-type specified.
       
    45 	 * Must be overridden in a sub-class.
       
    46 	 *
       
    47 	 * @since 3.5.0
       
    48 	 * @access public
       
    49 	 * @abstract
       
    50 	 *
       
    51 	 * @param string $mime_type
       
    52 	 * @return boolean
       
    53 	 */
       
    54 	public static function supports_mime_type( $mime_type ) {
       
    55 		return false;
       
    56 	}
       
    57 
       
    58 	/**
       
    59 	 * Loads image from $this->file into editor.
       
    60 	 *
       
    61 	 * @since 3.5.0
       
    62 	 * @access protected
       
    63 	 * @abstract
       
    64 	 *
       
    65 	 * @return boolean|WP_Error True if loaded; WP_Error on failure.
       
    66 	 */
       
    67 	abstract public function load();
       
    68 
       
    69 	/**
       
    70 	 * Saves current image to file.
       
    71 	 *
       
    72 	 * @since 3.5.0
       
    73 	 * @access public
       
    74 	 * @abstract
       
    75 	 *
       
    76 	 * @param string $destfilename
       
    77 	 * @param string $mime_type
       
    78 	 * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
       
    79 	 */
       
    80 	abstract public function save( $destfilename = null, $mime_type = null );
       
    81 
       
    82 	/**
       
    83 	 * Resizes current image.
       
    84 	 *
       
    85 	 * @since 3.5.0
       
    86 	 * @access public
       
    87 	 * @abstract
       
    88 	 *
       
    89 	 * @param int $max_w
       
    90 	 * @param int $max_h
       
    91 	 * @param boolean $crop
       
    92 	 * @return boolean|WP_Error
       
    93 	 */
       
    94 	abstract public function resize( $max_w, $max_h, $crop = false );
       
    95 
       
    96 	/**
       
    97 	 * Resize multiple images from a single source.
       
    98 	 *
       
    99 	 * @since 3.5.0
       
   100 	 * @access public
       
   101 	 * @abstract
       
   102 	 *
       
   103 	 * @param array $sizes {
       
   104 	 *     An array of image size arrays. Default sizes are 'small', 'medium', 'large'.
       
   105 	 *
       
   106 	 *     @type array $size {
       
   107 	 *         @type int  $width  Image width.
       
   108 	 *         @type int  $height Image height.
       
   109 	 *         @type bool $crop   Optional. Whether to crop the image. Default false.
       
   110 	 *     }
       
   111 	 * }
       
   112 	 * @return array An array of resized images metadata by size.
       
   113 	 */
       
   114 	abstract public function multi_resize( $sizes );
       
   115 
       
   116 	/**
       
   117 	 * Crops Image.
       
   118 	 *
       
   119 	 * @since 3.5.0
       
   120 	 * @access public
       
   121 	 * @abstract
       
   122 	 *
       
   123 	 * @param string|int $src The source file or Attachment ID.
       
   124 	 * @param int $src_x The start x position to crop from.
       
   125 	 * @param int $src_y The start y position to crop from.
       
   126 	 * @param int $src_w The width to crop.
       
   127 	 * @param int $src_h The height to crop.
       
   128 	 * @param int $dst_w Optional. The destination width.
       
   129 	 * @param int $dst_h Optional. The destination height.
       
   130 	 * @param boolean $src_abs Optional. If the source crop points are absolute.
       
   131 	 * @return boolean|WP_Error
       
   132 	 */
       
   133 	abstract public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false );
       
   134 
       
   135 	/**
       
   136 	 * Rotates current image counter-clockwise by $angle.
       
   137 	 *
       
   138 	 * @since 3.5.0
       
   139 	 * @access public
       
   140 	 * @abstract
       
   141 	 *
       
   142 	 * @param float $angle
       
   143 	 * @return boolean|WP_Error
       
   144 	 */
       
   145 	abstract public function rotate( $angle );
       
   146 
       
   147 	/**
       
   148 	 * Flips current image.
       
   149 	 *
       
   150 	 * @since 3.5.0
       
   151 	 * @access public
       
   152 	 * @abstract
       
   153 	 *
       
   154 	 * @param boolean $horz Flip along Horizontal Axis
       
   155 	 * @param boolean $vert Flip along Vertical Axis
       
   156 	 * @return boolean|WP_Error
       
   157 	 */
       
   158 	abstract public function flip( $horz, $vert );
       
   159 
       
   160 	/**
       
   161 	 * Streams current image to browser.
       
   162 	 *
       
   163 	 * @since 3.5.0
       
   164 	 * @access public
       
   165 	 * @abstract
       
   166 	 *
       
   167 	 * @param string $mime_type
       
   168 	 * @return boolean|WP_Error
       
   169 	 */
       
   170 	abstract public function stream( $mime_type = null );
       
   171 
       
   172 	/**
       
   173 	 * Gets dimensions of image.
       
   174 	 *
       
   175 	 * @since 3.5.0
       
   176 	 * @access public
       
   177 	 *
       
   178 	 * @return array {'width'=>int, 'height'=>int}
       
   179 	 */
       
   180 	public function get_size() {
       
   181 		return $this->size;
       
   182 	}
       
   183 
       
   184 	/**
       
   185 	 * Sets current image size.
       
   186 	 *
       
   187 	 * @since 3.5.0
       
   188 	 * @access protected
       
   189 	 *
       
   190 	 * @param int $width
       
   191 	 * @param int $height
       
   192 	 */
       
   193 	protected function update_size( $width = null, $height = null ) {
       
   194 		$this->size = array(
       
   195 			'width' => (int) $width,
       
   196 			'height' => (int) $height
       
   197 		);
       
   198 		return true;
       
   199 	}
       
   200 
       
   201 	/**
       
   202 	 * Sets Image Compression quality on a 1-100% scale.
       
   203 	 *
       
   204 	 * @since 3.5.0
       
   205 	 * @access public
       
   206 	 *
       
   207 	 * @param int $quality Compression Quality. Range: [1,100]
       
   208 	 * @return boolean
       
   209 	 */
       
   210 	public function set_quality( $quality ) {
       
   211 		/**
       
   212 		 * Filter the default quality setting.
       
   213 		 *
       
   214 		 * @since 3.5.0
       
   215 		 *
       
   216 		 * @param int $quality Quality level between 0 (low) and 100 (high).
       
   217 		 */
       
   218 		$this->quality = apply_filters( 'wp_editor_set_quality', $quality );
       
   219 
       
   220 		return ( (bool) $this->quality );
       
   221 	}
       
   222 
       
   223 	/**
       
   224 	 * Returns preferred mime-type and extension based on provided
       
   225 	 * file's extension and mime, or current file's extension and mime.
       
   226 	 *
       
   227 	 * Will default to $this->default_mime_type if requested is not supported.
       
   228 	 *
       
   229 	 * Provides corrected filename only if filename is provided.
       
   230 	 *
       
   231 	 * @since 3.5.0
       
   232 	 * @access protected
       
   233 	 *
       
   234 	 * @param string $filename
       
   235 	 * @param string $mime_type
       
   236 	 * @return array { filename|null, extension, mime-type }
       
   237 	 */
       
   238 	protected function get_output_format( $filename = null, $mime_type = null ) {
       
   239 		$new_ext = $file_ext = null;
       
   240 		$file_mime = null;
       
   241 
       
   242 		// By default, assume specified type takes priority
       
   243 		if ( $mime_type ) {
       
   244 			$new_ext = $this->get_extension( $mime_type );
       
   245 		}
       
   246 
       
   247 		if ( $filename ) {
       
   248 			$file_ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
       
   249 			$file_mime = $this->get_mime_type( $file_ext );
       
   250 		}
       
   251 		else {
       
   252 			// If no file specified, grab editor's current extension and mime-type.
       
   253 			$file_ext = strtolower( pathinfo( $this->file, PATHINFO_EXTENSION ) );
       
   254 			$file_mime = $this->mime_type;
       
   255 		}
       
   256 
       
   257 		// Check to see if specified mime-type is the same as type implied by
       
   258 		// file extension.  If so, prefer extension from file.
       
   259 		if ( ! $mime_type || ( $file_mime == $mime_type ) ) {
       
   260 			$mime_type = $file_mime;
       
   261 			$new_ext = $file_ext;
       
   262 		}
       
   263 
       
   264 		// Double-check that the mime-type selected is supported by the editor.
       
   265 		// If not, choose a default instead.
       
   266 		if ( ! $this->supports_mime_type( $mime_type ) ) {
       
   267 			/**
       
   268 			 * Filter default mime type prior to getting the file extension.
       
   269 			 *
       
   270 			 * @see wp_get_mime_types()
       
   271 			 *
       
   272 			 * @since 3.5.0
       
   273 			 *
       
   274 			 * @param string $mime_type Mime type string.
       
   275 			 */
       
   276 			$mime_type = apply_filters( 'image_editor_default_mime_type', $this->default_mime_type );
       
   277 			$new_ext = $this->get_extension( $mime_type );
       
   278 		}
       
   279 
       
   280 		if ( $filename ) {
       
   281 			$ext = '';
       
   282 			$info = pathinfo( $filename );
       
   283 			$dir  = $info['dirname'];
       
   284 
       
   285 			if( isset( $info['extension'] ) )
       
   286 				$ext = $info['extension'];
       
   287 
       
   288 			$filename = trailingslashit( $dir ) . wp_basename( $filename, ".$ext" ) . ".{$new_ext}";
       
   289 		}
       
   290 
       
   291 		return array( $filename, $new_ext, $mime_type );
       
   292 	}
       
   293 
       
   294 	/**
       
   295 	 * Builds an output filename based on current file, and adding proper suffix
       
   296 	 *
       
   297 	 * @since 3.5.0
       
   298 	 * @access public
       
   299 	 *
       
   300 	 * @param string $suffix
       
   301 	 * @param string $dest_path
       
   302 	 * @param string $extension
       
   303 	 * @return string filename
       
   304 	 */
       
   305 	public function generate_filename( $suffix = null, $dest_path = null, $extension = null ) {
       
   306 		// $suffix will be appended to the destination filename, just before the extension
       
   307 		if ( ! $suffix )
       
   308 			$suffix = $this->get_suffix();
       
   309 
       
   310 		$info = pathinfo( $this->file );
       
   311 		$dir  = $info['dirname'];
       
   312 		$ext  = $info['extension'];
       
   313 
       
   314 		$name = wp_basename( $this->file, ".$ext" );
       
   315 		$new_ext = strtolower( $extension ? $extension : $ext );
       
   316 
       
   317 		if ( ! is_null( $dest_path ) && $_dest_path = realpath( $dest_path ) )
       
   318 			$dir = $_dest_path;
       
   319 
       
   320 		return trailingslashit( $dir ) . "{$name}-{$suffix}.{$new_ext}";
       
   321 	}
       
   322 
       
   323 	/**
       
   324 	 * Builds and returns proper suffix for file based on height and width.
       
   325 	 *
       
   326 	 * @since 3.5.0
       
   327 	 * @access public
       
   328 	 *
       
   329 	 * @return string suffix
       
   330 	 */
       
   331 	public function get_suffix() {
       
   332 		if ( ! $this->get_size() )
       
   333 			return false;
       
   334 
       
   335 		return "{$this->size['width']}x{$this->size['height']}";
       
   336 	}
       
   337 
       
   338 	/**
       
   339 	 * Either calls editor's save function or handles file as a stream.
       
   340 	 *
       
   341 	 * @since 3.5.0
       
   342 	 * @access protected
       
   343 	 *
       
   344 	 * @param string|stream $filename
       
   345 	 * @param callable $function
       
   346 	 * @param array $arguments
       
   347 	 * @return boolean
       
   348 	 */
       
   349 	protected function make_image( $filename, $function, $arguments ) {
       
   350 		if ( $stream = wp_is_stream( $filename ) ) {
       
   351 			ob_start();
       
   352 		} else {
       
   353 			// The directory containing the original file may no longer exist when using a replication plugin.
       
   354 			wp_mkdir_p( dirname( $filename ) );
       
   355 		}
       
   356 
       
   357 		$result = call_user_func_array( $function, $arguments );
       
   358 
       
   359 		if ( $result && $stream ) {
       
   360 			$contents = ob_get_contents();
       
   361 
       
   362 			$fp = fopen( $filename, 'w' );
       
   363 
       
   364 			if ( ! $fp )
       
   365 				return false;
       
   366 
       
   367 			fwrite( $fp, $contents );
       
   368 			fclose( $fp );
       
   369 		}
       
   370 
       
   371 		if ( $stream ) {
       
   372 			ob_end_clean();
       
   373 		}
       
   374 
       
   375 		return $result;
       
   376 	}
       
   377 
       
   378 	/**
       
   379 	 * Returns first matched mime-type from extension,
       
   380 	 * as mapped from wp_get_mime_types()
       
   381 	 *
       
   382 	 * @since 3.5.0
       
   383 	 * @access protected
       
   384 	 *
       
   385 	 * @param string $extension
       
   386 	 * @return string|boolean
       
   387 	 */
       
   388 	protected static function get_mime_type( $extension = null ) {
       
   389 		if ( ! $extension )
       
   390 			return false;
       
   391 
       
   392 		$mime_types = wp_get_mime_types();
       
   393 		$extensions = array_keys( $mime_types );
       
   394 
       
   395 		foreach( $extensions as $_extension ) {
       
   396 			if ( preg_match( "/{$extension}/i", $_extension ) ) {
       
   397 				return $mime_types[$_extension];
       
   398 			}
       
   399 		}
       
   400 
       
   401 		return false;
       
   402 	}
       
   403 
       
   404 	/**
       
   405 	 * Returns first matched extension from Mime-type,
       
   406 	 * as mapped from wp_get_mime_types()
       
   407 	 *
       
   408 	 * @since 3.5.0
       
   409 	 * @access protected
       
   410 	 *
       
   411 	 * @param string $mime_type
       
   412 	 * @return string|boolean
       
   413 	 */
       
   414 	protected static function get_extension( $mime_type = null ) {
       
   415 		$extensions = explode( '|', array_search( $mime_type, wp_get_mime_types() ) );
       
   416 
       
   417 		if ( empty( $extensions[0] ) )
       
   418 			return false;
       
   419 
       
   420 		return $extensions[0];
       
   421 	}
       
   422 }
       
   423