Wordpress 3.6
[autoinstalls/wordpress.git] / wp-includes / class-wp-image-editor.php
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          * Processes current image and saves to disk
98          * multiple sizes from single source.
99          *
100          * 'width' and 'height' are required.
101          * 'crop' defaults to false when not provided.
102          *
103          * @since 3.5.0
104          * @access public
105          * @abstract
106          *
107          * @param array $sizes { {'width'=>int, 'height'=>int, ['crop'=>bool]}, ... }
108          * @return array
109          */
110         abstract public function multi_resize( $sizes );
111
112         /**
113          * Crops Image.
114          *
115          * @since 3.5.0
116          * @access public
117          * @abstract
118          *
119          * @param string|int $src The source file or Attachment ID.
120          * @param int $src_x The start x position to crop from.
121          * @param int $src_y The start y position to crop from.
122          * @param int $src_w The width to crop.
123          * @param int $src_h The height to crop.
124          * @param int $dst_w Optional. The destination width.
125          * @param int $dst_h Optional. The destination height.
126          * @param boolean $src_abs Optional. If the source crop points are absolute.
127          * @return boolean|WP_Error
128          */
129         abstract public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false );
130
131         /**
132          * Rotates current image counter-clockwise by $angle.
133          *
134          * @since 3.5.0
135          * @access public
136          * @abstract
137          *
138          * @param float $angle
139          * @return boolean|WP_Error
140          */
141         abstract public function rotate( $angle );
142
143         /**
144          * Flips current image.
145          *
146          * @since 3.5.0
147          * @access public
148          * @abstract
149          *
150          * @param boolean $horz Flip along Horizontal Axis
151          * @param boolean $vert Flip along Vertical Axis
152          * @return boolean|WP_Error
153          */
154         abstract public function flip( $horz, $vert );
155
156         /**
157          * Streams current image to browser.
158          *
159          * @since 3.5.0
160          * @access public
161          * @abstract
162          *
163          * @param string $mime_type
164          * @return boolean|WP_Error
165          */
166         abstract public function stream( $mime_type = null );
167
168         /**
169          * Gets dimensions of image.
170          *
171          * @since 3.5.0
172          * @access public
173          *
174          * @return array {'width'=>int, 'height'=>int}
175          */
176         public function get_size() {
177                 return $this->size;
178         }
179
180         /**
181          * Sets current image size.
182          *
183          * @since 3.5.0
184          * @access protected
185          *
186          * @param int $width
187          * @param int $height
188          */
189         protected function update_size( $width = null, $height = null ) {
190                 $this->size = array(
191                         'width' => (int) $width,
192                         'height' => (int) $height
193                 );
194                 return true;
195         }
196
197         /**
198          * Sets Image Compression quality on a 1-100% scale.
199          *
200          * @since 3.5.0
201          * @access public
202          *
203          * @param int $quality Compression Quality. Range: [1,100]
204          * @return boolean
205          */
206         public function set_quality( $quality ) {
207                 $this->quality = apply_filters( 'wp_editor_set_quality', $quality );
208
209                 return ( (bool) $this->quality );
210         }
211
212         /**
213          * Returns preferred mime-type and extension based on provided
214          * file's extension and mime, or current file's extension and mime.
215          *
216          * Will default to $this->default_mime_type if requested is not supported.
217          *
218          * Provides corrected filename only if filename is provided.
219          *
220          * @since 3.5.0
221          * @access protected
222          *
223          * @param string $filename
224          * @param string $mime_type
225          * @return array { filename|null, extension, mime-type }
226          */
227         protected function get_output_format( $filename = null, $mime_type = null ) {
228                 $new_ext = $file_ext = null;
229                 $file_mime = null;
230
231                 // By default, assume specified type takes priority
232                 if ( $mime_type ) {
233                         $new_ext = $this->get_extension( $mime_type );
234                 }
235
236                 if ( $filename ) {
237                         $file_ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
238                         $file_mime = $this->get_mime_type( $file_ext );
239                 }
240                 else {
241                         // If no file specified, grab editor's current extension and mime-type.
242                         $file_ext = strtolower( pathinfo( $this->file, PATHINFO_EXTENSION ) );
243                         $file_mime = $this->mime_type;
244                 }
245
246                 // Check to see if specified mime-type is the same as type implied by
247                 // file extension.  If so, prefer extension from file.
248                 if ( ! $mime_type || ( $file_mime == $mime_type ) ) {
249                         $mime_type = $file_mime;
250                         $new_ext = $file_ext;
251                 }
252
253                 // Double-check that the mime-type selected is supported by the editor.
254                 // If not, choose a default instead.
255                 if ( ! $this->supports_mime_type( $mime_type ) ) {
256                         $mime_type = apply_filters( 'image_editor_default_mime_type', $this->default_mime_type );
257                         $new_ext = $this->get_extension( $mime_type );
258                 }
259
260                 if ( $filename ) {
261                         $ext = '';
262                         $info = pathinfo( $filename );
263                         $dir  = $info['dirname'];
264
265                         if( isset( $info['extension'] ) )
266                                 $ext = $info['extension'];
267
268                         $filename = trailingslashit( $dir ) . wp_basename( $filename, ".$ext" ) . ".{$new_ext}";
269                 }
270
271                 return array( $filename, $new_ext, $mime_type );
272         }
273
274         /**
275          * Builds an output filename based on current file, and adding proper suffix
276          *
277          * @since 3.5.0
278          * @access public
279          *
280          * @param string $suffix
281          * @param string $dest_path
282          * @param string $extension
283          * @return string filename
284          */
285         public function generate_filename( $suffix = null, $dest_path = null, $extension = null ) {
286                 // $suffix will be appended to the destination filename, just before the extension
287                 if ( ! $suffix )
288                         $suffix = $this->get_suffix();
289
290                 $info = pathinfo( $this->file );
291                 $dir  = $info['dirname'];
292                 $ext  = $info['extension'];
293
294                 $name = wp_basename( $this->file, ".$ext" );
295                 $new_ext = strtolower( $extension ? $extension : $ext );
296
297                 if ( ! is_null( $dest_path ) && $_dest_path = realpath( $dest_path ) )
298                         $dir = $_dest_path;
299
300                 return trailingslashit( $dir ) . "{$name}-{$suffix}.{$new_ext}";
301         }
302
303         /**
304          * Builds and returns proper suffix for file based on height and width.
305          *
306          * @since 3.5.0
307          * @access public
308          *
309          * @return string suffix
310          */
311         public function get_suffix() {
312                 if ( ! $this->get_size() )
313                         return false;
314
315                 return "{$this->size['width']}x{$this->size['height']}";
316         }
317
318         /**
319          * Either calls editor's save function or handles file as a stream.
320          *
321          * @since 3.5.0
322          * @access protected
323          *
324          * @param string|stream $filename
325          * @param callable $function
326          * @param array $arguments
327          * @return boolean
328          */
329         protected function make_image( $filename, $function, $arguments ) {
330                 if ( $stream = wp_is_stream( $filename ) ) {
331                         ob_start();
332                 } else {
333                         // The directory containing the original file may no longer exist when using a replication plugin. 
334                         wp_mkdir_p( dirname( $filename ) ); 
335                 }
336
337                 $result = call_user_func_array( $function, $arguments );
338
339                 if ( $result && $stream ) {
340                         $contents = ob_get_contents();
341
342                         $fp = fopen( $filename, 'w' );
343
344                         if ( ! $fp )
345                                 return false;
346
347                         fwrite( $fp, $contents );
348                         fclose( $fp );
349                 }
350
351                 if ( $stream ) {
352                         ob_end_clean();
353                 }
354
355                 return $result;
356         }
357
358         /**
359          * Returns first matched mime-type from extension,
360          * as mapped from wp_get_mime_types()
361          *
362          * @since 3.5.0
363          * @access protected
364          *
365          * @param string $extension
366          * @return string|boolean
367          */
368         protected static function get_mime_type( $extension = null ) {
369                 if ( ! $extension )
370                         return false;
371
372                 $mime_types = wp_get_mime_types();
373                 $extensions = array_keys( $mime_types );
374
375                 foreach( $extensions as $_extension ) {
376                         if ( preg_match( "/{$extension}/i", $_extension ) ) {
377                                 return $mime_types[$_extension];
378                         }
379                 }
380
381                 return false;
382         }
383
384         /**
385          * Returns first matched extension from Mime-type,
386          * as mapped from wp_get_mime_types()
387          *
388          * @since 3.5.0
389          * @access protected
390          *
391          * @param string $mime_type
392          * @return string|boolean
393          */
394         protected static function get_extension( $mime_type = null ) {
395                 $extensions = explode( '|', array_search( $mime_type, wp_get_mime_types() ) );
396
397                 if ( empty( $extensions[0] ) )
398                         return false;
399
400                 return $extensions[0];
401         }
402 }
403