<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName /** * The Image Class. * * @package automattic/jetpack */ /** * Represents a resizable image, exposing properties necessary for properly generating srcset. */ class Jetpack_Photon_Image { /** * Attachment's Filename. * * @var string */ public $filename; /** * Attachment's mime-type, WP_Error on failure when recalculating the dimensions. * * @var string|WP_Error */ private $mime_type; /** * Image original width. * * @var int */ private $original_width; /** * Image original height. * * @var int */ private $original_height; /** * Current attachment's width. * * @var int */ private $width; /** * Current attachment's height. * * @var int */ private $height; /** * Whether the attachment has been resized yet, or not. * * @var bool */ private $is_resized = false; /** * Constructs the image object. * * The $data array should provide at least * file : string Image file path * width : int Image width * height : int Image height * * @param array $data Array of attachment metadata, typically value of _wp_attachment_metadata postmeta. * @param string|\WP_Error $mime_type Typically value returned from get_post_mime_type function. */ public function __construct( $data, $mime_type ) { $this->filename = $data['file']; $this->original_width = $data['width']; $this->original_height = $data['height']; $this->width = $this->original_width; $this->height = $this->original_height; $this->mime_type = $mime_type; } /** * Resizes the image to given size. * * @param array $size_data Array of width, height, and crop properties of a size. * * @return bool|\WP_Error True if resize was successful, WP_Error on failure. */ public function resize( $size_data ) { $dimensions = $this->image_resize_dimensions( $size_data['width'], $size_data['height'], $size_data['crop'] ); if ( true === is_wp_error( $dimensions ) ) { return $dimensions; // Returns \WP_Error. } if ( true === is_wp_error( $this->mime_type ) ) { return $this->mime_type; // Returns \WP_Error. } $this->set_width_height( $dimensions ); $this->is_resized = true; return true; } /** * Generates size data for usage in $metadata['sizes'];. * * @param array $size_data Array of width, height, and crop properties of a size. * * @return array|\WP_Error An array containing file, width, height, and mime-type keys and it's values. WP_Error on failure. */ public function get_size( $size_data ) { $is_resized = $this->resize( $size_data ); if ( true === is_wp_error( $is_resized ) ) { return $is_resized; } return array( 'file' => $this->get_filename(), 'width' => $this->get_width(), 'height' => $this->get_height(), 'mime-type' => $this->get_mime_type(), ); } /** * Resets the image to it's original dimensions. * * @return bool True on successful reset to original dimensions. */ public function reset_to_original() { $this->width = $this->original_width; $this->height = $this->original_height; $this->is_resized = false; return true; } /** * Return the basename filename. If the image has been resized, including * the resizing params for Jetpack CDN. * * @return string Basename of the filename. */ public function get_filename() { return wp_basename( $this->get_raw_filename() ); } /** * Return the absolute filename. If the image has been resized, including * the resizing params for Jetpack CDN. * * @return string Filename. */ public function get_raw_filename() { return $this->is_resized() ? $this->get_resized_filename() : $this->filename; } /** * Returns current image width. Either original, or after resize. * * @return int */ public function get_width() { return (int) $this->width; } /** * Returns current image height. Either original, or after resize. * * @return int */ public function get_height() { return (int) $this->height; } /** * Returns image mime type. * * @return string|WP_Error Image's mime type or WP_Error if it was not determined. */ public function get_mime_type() { return $this->mime_type; } /** * Checks the resize status of the image. * * @return bool If the image has been resized. */ public function is_resized() { return ( true === $this->is_resized ); } /** * Get filename with proper args for the Photon service. * * @return string Filename with query args for Photon service */ protected function get_resized_filename() { $query_args = array( 'resize' => join( ',', array( $this->get_width(), $this->get_height(), ) ), ); return add_query_arg( $query_args, $this->filename ); } /** * Get resize dimensions used for the Jetpack CDN service. * * Converts the list of values returned from `image_resize_dimensions()` to * associative array for the sake of more readable code no relying on index * nor `list`. * * @param int $max_width Maximum width. * @param int $max_height Maximum height. * @param bool|array $crop Cropping parameters. * * @return array|\WP_Error Array of dimensions matching the parameters to imagecopyresampled. WP_Error on failure. */ protected function image_resize_dimensions( $max_width, $max_height, $crop ) { $dimensions = image_resize_dimensions( $this->original_width, $this->original_height, $max_width, $max_height, $crop ); if ( ! $dimensions ) { return new WP_Error( 'error_getting_dimensions', __( 'Could not calculate resized image dimensions', 'jetpack' ), $this->filename ); } return array_combine( array( 'dst_x', 'dst_y', 'src_x', 'src_y', 'dst_w', 'dst_h', 'src_w', 'src_h', ), $dimensions ); } /** * Sets proper width and height from dimensions. * * @param array $dimensions an array of image dimensions. * @return void */ protected function set_width_height( $dimensions ) { $this->width = (int) $dimensions['dst_w']; $this->height = (int) $dimensions['dst_h']; } }