home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / class-wp-image-editor.php < prev    next >
Encoding:
PHP Script  |  2017-08-22  |  11.4 KB  |  471 lines

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