PageRenderTime 56ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-includes/class-wp-image-editor.php

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