* @author Alan Knowles * @author Peter Bowyer * @author Philippe Jausions * @copyright 2002-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/Image_Transform */ /** * Include for error handling */ require_once 'PEAR.php'; /** * Error code for unsupported library, image format or methods */ define('IMAGE_TRANSFORM_ERROR_UNSUPPORTED', 1); /** * Error code for failed transformation operations */ define('IMAGE_TRANSFORM_ERROR_FAILED', 2); /** * Error code for failed i/o (Input/Output) operations */ define('IMAGE_TRANSFORM_ERROR_IO', 3); /** * Error code for invalid arguments */ define('IMAGE_TRANSFORM_ERROR_ARGUMENT', 4); /** * Error code for out-of-bound related errors */ define('IMAGE_TRANSFORM_ERROR_OUTOFBOUND', 5); /** * Base class with factory method for backend driver * * The main "Image_Transform" class is a container and base class which * provides a static method for creating an Image object as well as * some utility functions (maths) common to all parts of Image_Transform. * * @category Image * @package Image_Transform * @author Alan Knowles * @author Peter Bowyer * @author Philippe Jausions * @copyright 2002-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/Image_Transform * @since PHP 4.0 */ class Image_Transform { /** * Name of the image file * @var string */ var $image = ''; /** * Type of the image file (eg. jpg, gif png ...) * @var string */ var $type = ''; /** * Original image width in x direction * @var int */ var $img_x = ''; /** * Original image width in y direction * @var int */ var $img_y = ''; /** * New image width in x direction * @var int */ var $new_x = ''; /** * New image width in y direction * @var int */ var $new_y = ''; /** * Path to the library used * e.g. /usr/local/ImageMagick/bin/ or * /usr/local/netpbm/ */ var $lib_path = ''; /** * Flag to warn if image has been resized more than once before displaying * or saving. */ var $resized = false; /** * @var array General options * @access protected */ var $_options = array( 'quality' => 75, 'scaleMethod' => 'smooth', 'canvasColor' => array(255, 255, 255), 'pencilColor' => array(0, 0, 0), 'textColor' => array(0, 0, 0) ); /** * Flag for whether settings should be discarded on saving/display of image * @var bool * @see Image_Transform::keepSettingsOnSave */ var $keep_settings_on_save = false; /** * Supported image types * @var array * @access protected */ var $_supported_image_types = array(); /** * Initialization error tracking * @var object * @access private **/ var $_error = null; /** * associative array that tracks existence of programs * (for drivers using shell interface and a tiny performance * improvement if the clearstatcache() is used) * @var array * @access protected */ var $_programs = array(); /** * Default parameters used in the addText methods. */ var $default_text_params = array('text' => 'Default text', 'x' => 10, 'y' => 20, 'color' => 'red', 'font' => 'Arial.ttf', 'size' => '12', 'angle' => 0, 'resize_first' => false); /** * Creates a new Image_Transform object * * @param string $driver name of driver class to initialize. If no driver * is specified the factory will attempt to use 'Imagick' first * then 'GD' second, then 'Imlib' last * * @return object an Image_Transform object, or PEAR_Error on error * * @see PEAR::isError() * @see Image_Transform::setOption() */ function &factory($driver = '') { if ($driver == '') { $extensions = array( 'imagick' => 'Imagick2', 'gd' => 'GD', 'imlib' => 'Imlib'); foreach ($extensions as $ext => $ext_driver) { if (PEAR::loadExtension($ext)) { $driver = $ext_driver; break; } } if (!$driver) { return PEAR::raiseError('No image library specified and none can be found. You must specify driver in factory() call.', IMAGE_TRANSFORM_ERROR_ARGUMENT); } } @include_once 'Image/Transform/Driver/' . basename($driver) . '.php'; $classname = "Image_Transform_Driver_{$driver}"; if (!class_exists($classname)) { return PEAR::raiseError('Image library not supported... aborting.', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } $obj =& new $classname; // Check startup error if ($error =& $obj->isError()) { $obj =& $error; } return $obj; } /** * Returns/sets an error when the instance couldn't initialize properly * * @param object PEAR_Error object when setting an error * @return mixed FALSE or PEAR_Error object * @access protected */ function &isError($error = null) { if (!is_null($error)) { $this->_error =& $error; } return $this->_error; } /** * Resizes the image in the X and/or Y direction(s) * * If either is 0 it will keep the original size for that dimension * * @param mixed $new_x (0, number, percentage 10% or 0.1) * @param mixed $new_y (0, number, percentage 10% or 0.1) * @param array $options Options * @return mixed TRUE or PEAR_Error object on error * @access public */ function resize($new_x = 0, $new_y = 0, $options = null) { // 0 means keep original size $new_x = (0 == $new_x) ? $this->img_x : $this->_parse_size($new_x, $this->img_x); $new_y = (0 == $new_y) ? $this->img_y : $this->_parse_size($new_y, $this->img_y); // Now do the library specific resizing. return $this->_resize($new_x, $new_y, $options); } // End resize /** * Scales the image to the specified width * * This method preserves the aspect ratio * * @param int $new_x Size to scale X-dimension to * @return mixed TRUE or PEAR_Error object on error * @access public */ function scaleByX($new_x) { if ($new_x <= 0) { return PEAR::raiseError('New size must be strictly positive', IMAGE_TRANSFORM_ERROR_OUTOFBOUND); } $new_y = round(($new_x / $this->img_x) * $this->img_y, 0); return $this->_resize(max(1, $new_x), max(1, $new_y)); } // End scaleByX /** * Alias for resize() * * @see resize() */ function scaleByXY($new_x = 0, $new_y = 0, $options = null) { return $this->resize($new_x, $new_y, $options); } // End scaleByXY /** * Scales the image to the specified height. * * This method preserves the aspect ratio * * @param int $new_y Size to scale Y-dimension to * @return mixed TRUE or PEAR_Error object on error * @access public */ function scaleByY($new_y) { if ($new_y <= 0) { return PEAR::raiseError('New size must be strictly positive', IMAGE_TRANSFORM_ERROR_OUTOFBOUND); } $new_x = round(($new_y / $this->img_y) * $this->img_x, 0); return $this->_resize(max(1, $new_x), max(1, $new_y)); } // End scaleByY /** * Scales an image by a percentage, factor or a given length * * This method preserves the aspect ratio * * @param mixed (number, percentage 10% or 0.1) * @return mixed TRUE or PEAR_Error object on error * @access public * @see scaleByPercentage, scaleByFactor, scaleByLength */ function scale($size) { if ((strlen($size) > 1) && (substr($size, -1) == '%')) { return $this->scaleByPercentage(substr($size, 0, -1)); } elseif ($size < 1) { return $this->scaleByFactor($size); } else { return $this->scaleByLength($size); } } // End scale /** * Scales an image to a percentage of its original size. For example, if * my image was 640x480 and I called scaleByPercentage(10) then the image * would be resized to 64x48 * * @param int $size Percentage of original size to scale to * @return mixed TRUE or PEAR_Error object on error * @access public */ function scaleByPercentage($size) { return $this->scaleByFactor($size / 100); } // End scaleByPercentage /** * Scales an image to a factor of its original size. For example, if * my image was 640x480 and I called scaleByFactor(0.5) then the image * would be resized to 320x240. * * @param float $size Factor of original size to scale to * @return mixed TRUE or PEAR_Error object on error * @access public */ function scaleByFactor($size) { if ($size <= 0) { return PEAR::raiseError('New size must be strictly positive', IMAGE_TRANSFORM_ERROR_OUTOFBOUND); } $new_x = round($size * $this->img_x, 0); $new_y = round($size * $this->img_y, 0); return $this->_resize(max(1, $new_x), max(1, $new_y)); } // End scaleByFactor /** * Scales an image so that the longest side has the specified dimension. * * This method preserves the aspect ratio * * @param int $size Max dimension in pixels * @return mixed TRUE or PEAR_Error object on error * @access public */ function scaleMaxLength($size) { if ($size <= 0) { return PEAR::raiseError('New size must be strictly positive', IMAGE_TRANSFORM_ERROR_OUTOFBOUND); } if ($this->img_x >= $this->img_y) { $new_x = $size; $new_y = round(($new_x / $this->img_x) * $this->img_y, 0); } else { $new_y = $size; $new_x = round(($new_y / $this->img_y) * $this->img_x, 0); } return $this->_resize(max(1, $new_x), max(1, $new_y)); } // End scaleMaxLength /** * Alias for scaleMaxLength * * @return mixed TRUE or PEAR_Error object on error * @access public * @see scaleMaxLength() */ function scaleByLength($size) { return $this->scaleMaxLength($size); } /** * Fits the image in the specified box size * * If the image is bigger than the box specified by $width and $height, * it will be scaled down to fit inside of it. * If the image is smaller, nothing is done. * * @param integer $width * @param integer $height * @return bool|PEAR_Error TRUE or PEAR_Error object on error * @access public */ function fit($width, $height) { if ($width <= 0 || $height <= 0) { return PEAR::raiseError("Invalid arguments.", IMAGE_TRANSFORM_ERROR_ARGUMENT); } $x = $this->img_x / $width; $y = $this->img_y / $height; if ($x <= 1 && $y <= 1) { return true; } elseif ($x > $y) { return $this->scaleByX($width); } else { return $this->scaleByY($height); } } /** * Fits the image in the specified width * * If the image is wider than the width specified by $width, * it will be scaled down to fit inside of it. * If the image is smaller, nothing is done. * * @param integer $width * @return bool|PEAR_Error TRUE or PEAR_Error object on error * @access public */ function fitX($width) { return ($this->img_x <= $width) ? true : $this->scaleByX($width); } /** * Fits the image in the specified height * * If the image is taller than the height specified by $height, * it will be scaled down to fit inside of it. * If the image is smaller, nothing is done. * * @param integer $height * @return bool|PEAR_Error TRUE or PEAR_Error object on error * @access public */ function fitY($height) { return ($this->img_y <= $height) ? true : $this->scaleByY($height); } /** * Sets one options * * @param string Name of option * @param mixed Value of option * @access public * @see setOptions() */ function setOption($name, $value) { $this->_options[$name] = $value; } /** * Sets multiple options at once * * Associative array of options: * - quality (Integer: 0: poor - 100: best) * - scaleMethod ('smooth', 'pixel') * * @param array $options Array of options * @access public */ function setOptions($options) { $this->_options = array_merge($this->_options, $options); } /** * Sets the image type (in lowercase letters), the image height and width. * * @return mixed TRUE or PEAR_error * @access protected * @see PHP_Compat::image_type_to_mime_type() * @link http://php.net/getimagesize */ function _get_image_details($image) { $data = @getimagesize($image); // 1 = GIF, 2 = JPG, 3 = PNG, 4 = SWF, 5 = PSD, 6 = BMP, // 7 = TIFF (intel byte order), 8 = TIFF (motorola byte order), // 9 = JPC, 10 = JP2, 11 = JPX, 12 = JB2, 13 = SWC, 14 = IFF, // 15 = WBMP, 16 = XBM if (!is_array($data)) { return PEAR::raiseError("Cannot fetch image or images details.", true); } switch ($data[2]) { case IMAGETYPE_GIF: $type = 'gif'; break; case IMAGETYPE_JPEG: $type = 'jpeg'; break; case IMAGETYPE_PNG: $type = 'png'; break; case IMAGETYPE_SWF: $type = 'swf'; break; case IMAGETYPE_PSD: $type = 'psd'; break; case IMAGETYPE_BMP: $type = 'bmp'; break; case IMAGETYPE_TIFF_II: case IMAGETYPE_TIFF_MM: $type = 'tiff'; break; case IMAGETYPE_JPC: $type = 'jpc'; break; case IMAGETYPE_JP2: $type = 'jp2'; break; case IMAGETYPE_JPX: $type = 'jpx'; break; case IMAGETYPE_JB2: $type = 'jb2'; break; case IMAGETYPE_SWC: $type = 'swc'; break; case IMAGETYPE_IFF: $type = 'iff'; break; case IMAGETYPE_WBMP: $type = 'wbmp'; break; case IMAGETYPE_XBM: $type = 'xbm'; break; default: return PEAR::raiseError("Cannot recognize image format", IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } $this->img_x = $this->new_x = $data[0]; $this->img_y = $this->new_y = $data[1]; $this->type = $type; return true; } /** * Returns the matching IMAGETYPE_* constant for a given image type * * @param mixed $type String (GIF, JPG,...) * @return mixed string or integer or input on error * @access protected * @see PHP_Compat::image_type_to_mime_type() **/ function _convert_image_type($type) { switch (strtolower($type)) { case 'gif': return IMAGETYPE_GIF; case 'jpeg': case 'jpg': return IMAGETYPE_JPEG; case 'png': return IMAGETYPE_PNG; case 'swf': return IMAGETYPE_SWF; case 'psd': return IMAGETYPE_PSD; case 'bmp': return IMAGETYPE_BMP; case 'tiff': return IMAGETYPE_TIFF_II; //IMAGETYPE_TIFF_MM; case 'jpc': return IMAGETYPE_JPC; case 'jp2': return IMAGETYPE_JP2; case 'jpx': return IMAGETYPE_JPX; case 'jb2': return IMAGETYPE_JB2; case 'swc': return IMAGETYPE_SWC; case 'iff': return IMAGETYPE_IFF; case 'wbmp': return IMAGETYPE_WBMP; case 'xbm': return IMAGETYPE_XBM; default: return $type; } return (isset($types[$t = strtolower($type)])) ? $types[$t] : $type; } /** * Parses input for number format and convert * * If either parameter is 0 it will be scaled proportionally * * @param mixed $new_size (0, number, percentage 10% or 0.1) * @param int $old_size * @return mixed Integer or PEAR_error * @access protected */ function _parse_size($new_size, $old_size) { if (substr($new_size, -1) == '%') { $new_size = substr($new_size, 0, -1); $new_size = $new_size / 100; } if ($new_size > 1) { return (int) $new_size; } elseif ($new_size == 0) { return (int) $old_size; } else { return (int) round($new_size * $old_size, 0); } } /** * Returns an angle between 0 and 360 from any angle value * * @param float $angle The angle to normalize * @return float the angle * @access protected */ function _rotation_angle($angle) { $angle %= 360; return ($angle < 0) ? $angle + 360 : $angle; } /** * Returns the current value of $this->default_text_params. * * @return array $this->default_text_params The current text parameters * @access protected */ function _get_default_text_params() { return $this->default_text_params; } /** * Sets the image width * * @param int $size dimension to set * @access protected * @since 29/05/02 13:36:31 */ function _set_img_x($size) { $this->img_x = $size; } /** * Sets the image height * * @param int $size dimension to set * @access protected * @since 29/05/02 13:36:31 */ function _set_img_y($size) { $this->img_y = $size; } /** * Sets the new image width * * @param int $size dimension to set * @access protected * @since 29/05/02 13:36:31 */ function _set_new_x($size) { $this->new_x = $size; } /** * Sets the new image height * * @param int $size dimension to set * @since 29/05/02 13:36:31 * @access protected */ function _set_new_y($size) { $this->new_y = $size; } /** * Returns the type of the image being manipulated * * @return string the image type * @access public */ function getImageType() { return $this->type; } /** * Returns the MIME type of the image being manipulated * * @param string $type Image type to get MIME type for * @return string The MIME type if available, or an empty string * @access public * @see PHP_Compat::image_type_to_mime_type() * @link http://php.net/image_type_to_mime_type */ function getMimeType($type = null) { return image_type_to_mime_type($this->_convert_image_type(($type) ? $type : $this->type)); } /** * Returns the image width * * @return int the width of the image * @access public */ function getImageWidth() { return $this->img_x; } /** * Returns the image height * * @return int the width of the image * @access public */ function getImageHeight() { return $this->img_y; } /** * Returns the image size and extra format information * * @return array The width and height of the image * @access public * @see PHP::getimagesize() */ function getImageSize() { return array( $this->img_x, $this->img_y, $this->_convert_image_type($this->type), 'height="' . $this->img_y . '" width="' . $this->img_x . '"', 'mime' => $this->getMimeType()); } /** * This looks at the current image type and attempts to determine which * web-safe format will be most suited. It does not work brilliantly with * *.png images, because it is very difficult to know whether they are * 8-bit or greater. Guess I need to have fatter code here :-) * * @return string web-safe image type * @access public */ function getWebSafeFormat() { switch ($this->type){ case 'gif': case 'png': return 'png'; break; default: return 'jpeg'; } // switch } /** * Handles space in path and Windows/UNIX difference * * @param string $path Base dir * @param string $command Command to execute * @param string $args Arguments to pass to the command * @return string A prepared string suitable for exec() * @access protected */ function _prepare_cmd($path, $command, $args = '') { if (!OS_WINDOWS || !preg_match('/\s/', $path)) { return $path . $command . ' ' . $args; } return 'start /D "' . $path . '" /B ' . $command . ' ' . $args; } /** * Place holder for the real resize method * used by extended methods to do the resizing * * @return PEAR_error * @access protected */ function _resize() { return PEAR::raiseError('Resize method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Loads an image file to work with * * Place holder for the real load method * used by extended methods to do the resizing * * @return PEAR_error * @access public */ function load($filename) { return PEAR::raiseError('load() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Outputs the image to standard output * * Place holder for the real display method * used by extended methods to do the resizing * * @param string $type Format of image to save as * @param mixed $quality Format-dependent * @return PEAR_error * @access public */ function display($type, $quality = null) { return PEAR::raiseError('display() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Returns if the driver supports a given image type * * @param string $type Image type (GIF, PNG, JPEG...) * @param string $mode 'r' for read, 'w' for write, 'rw' for both * @return TRUE if type (and mode) is supported FALSE otherwise * @access public */ function supportsType($type, $mode = 'rw') { return (strpos(@$this->_supported_image_types[strtolower($type)], $mode) === false) ? false : true; } /** * Saves image to file * * Place holder for the real save method * used by extended methods to do the resizing * * @param string $filename Filename to save image to * @param string $type Format of image to save as * @param mixed $quality Format-dependent * @return PEAR_error * @access public */ function save($filename, $type, $quality = null) { return PEAR::raiseError('save() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Releases resource * * Place holder for the real free method * used by extended methods to do the resizing * * @return PEAR_error * @access public */ function free() { return PEAR::raiseError('free() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Converts a color string into an array of RGB values * * @param string $colorhex A color following the #FFFFFF format * @return array 3-element array with 0-255 values * @access public * * @see rgb2colorname * @see colorarray2colorhex */ function colorhex2colorarray($colorhex) { $r = hexdec(substr($colorhex, 1, 2)); $g = hexdec(substr($colorhex, 3, 2)); $b = hexdec(substr($colorhex, 5, 2)); return array($r, $g, $b, 'type' => 'RGB'); } function _send_display_headers($type) { // Find the filename of the original image: $filename = explode('.', basename($this->image)); $filename = $filename[0]; header('Content-type: ' . $this->getMimeType($type)); header ('Content-Disposition: inline; filename=' . $filename . '.' . $type ); } /** * Converts an array of RGB value into a #FFFFFF format color. * * @param array $color 3-element array with 0-255 values * @return mixed A color following the #FFFFFF format or FALSE * if the array couldn't be converted * @access public * * @see rgb2colorname * @see colorhex2colorarray */ function colorarray2colorhex($color) { if (!is_array($color)) { return false; } $color = sprintf('#%02X%02X%02X', @$color[0], @$color[1], @$color[2]); return (strlen($color) != 7) ? false : $color; } /*** These snitched from the File package. Saves including another class! ***/ /** * Returns the temp directory according to either the TMP, TMPDIR, or TEMP env * variables. If these are not set it will also check for the existence of * /tmp, %WINDIR%\temp * * @access public * @return string The system tmp directory */ function getTempDir() { include_once 'System.php'; return System::tmpdir(); } /** * Returns a temporary filename using tempnam() and the above getTmpDir() function. * * @access public * @param string $dirname Optional directory name for the tmp file * @return string Filename and path of the tmp file */ function getTempFile($dirname = NULL) { return tempnam((is_null($dirname)) ? System::tmpdir() : $dirname, 'temp.'); } function keepSettingsOnSave($bool) { $this->keep_settings_on_save = $bool; } /* Methods to add to the driver classes in the future */ function addText() { return PEAR::raiseError('addText() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } function addDropShadow() { return PEAR::raiseError('addDropShadow() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } function addBorder() { return PEAR::raiseError('addBorder() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Crops an image * * @param int width Cropped image width * @param int height Cropped image height * @param int x X-coordinate to crop at * @param int y Y-coordinate to crop at * * @return mixed TRUE or a PEAR_Error object on error * @access public **/ function crop($width, $height, $x = 0, $y = 0) { return PEAR::raiseError('crop() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } function canvasResize() { return PEAR::raiseError('canvasResize() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Corrects the gamma of an image * * @param float $outputgamma Gamma correction factor * @return mixed TRUE or a PEAR_error object on error * @access public **/ function gamma($outputgamma = 1.0) { return PEAR::raiseError('gamma() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Rotates the image clockwise * * @param float $angle angle of rotation in degres * @param mixed $options * @return bool|PEAR_Error TRUE on success, PEAR_Error object on error * @access public */ function rotate($angle, $options = null) { return PEAR::raiseError('rotate() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Horizontal mirroring * * @return mixed TRUE or PEAR_Error object on error * @access public * @see flip() **/ function mirror() { return PEAR::raiseError('mirror() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Vertical mirroring * * @return TRUE or PEAR Error object on error * @access public * @see mirror() **/ function flip() { return PEAR::raiseError('flip() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * Converts an image into greyscale colors * * @return mixed TRUE or a PEAR error object on error * @access public **/ function greyscale() { return PEAR::raiseError('greyscale() method not supported by driver', IMAGE_TRANSFORM_ERROR_UNSUPPORTED); } /** * @see greyscale() **/ function grayscale() { return $this->greyscale(); } /** * Returns a color option * * @param string $colorOf one of 'canvasColor', 'pencilColor', 'fontColor' * @param array $options * @param array $default default value to return if color not found * @return array an RGB color array * @access protected */ function _getColor($colorOf, $options = array(), $default = array(0, 0, 0)) { $opt = array_merge($this->_options, (array) $options); if (isset($opt[$colorOf])) { $color = $opt[$colorOf]; if (is_array($color)) { return $color; } if ($color{0} == '#') { return $this->colorhex2colorarray($color); } static $colornames = array(); include_once 'Image/Transform/Driver/ColorsDefs.php'; return (isset($colornames[$color])) ? $colornames[$color] : $default; } return $default; } /** * Returns an option * * @param string $name name of option * @param array $options local override option array * @param mixed $default default value to return if option is not found * @return mixed the option * @access protected */ function _getOption($name, $options = array(), $default = null) { $opt = array_merge($this->_options, (array) $options); return (isset($opt[$name])) ? $opt[$name] : $default; } /** * Checks if the rectangle passed intersects with the current image * * @param int $width * @param int $height * @param int $x X-coordinate * @param int $y Y-coordinate * @return bool|PEAR_Error TRUE if intersects, FALSE if not, and PEAR_Error on error * @access public */ function intersects($width, $height, $x, $y) { $left = $x; $right = $x + $width; if ($right < $left) { $left = $right; $right = $x; } $top = $y; $bottom = $y + $height; if ($bottom < $top) { $top = $bottom; $bottom = $y; } return (bool) ($left < $this->new_x && $right >= 0 && $top < $this->new_y && $bottom >= 0); } }