/ */ class P4Cms_Image_Driver_Gd extends P4Cms_Image_Driver_Abstract { protected static $_requiredExtension = 'gd'; protected static $_supportedTransforms = array( 'scale', 'sharpen', 'crop', 'rotate' ); protected $_resource = null; protected $_type = null; /** * Set the image data. * * @param string|null $data optional - image data * @return P4Cms_Image_Driver_Gd provides fluent interface */ public function setData($data = null) { if ($data) { $this->_resource = imagecreatefromstring($data); $this->_type = $this->_getType($data); } else { $this->_resource = null; $this->_type = null; } return $this; } /** * Return binary image data. * * @param string $type optional - the image format (will return image data * in the same format as input if not provided) * @return string|null binary image data or null if no image data were set */ public function getData($type = null) { // early exit if there are no image data if (!$this->hasData()) { return null; } // if no image type was provided, use the type of input image $type = $type ?: $this->_type; // check if given type is supported if (!static::isSupportedType($type)) { throw new P4Cms_Image_Exception("Image type '$type' is not supported."); } // assemble callback to get the image data in a given type // @todo should we normalize jpg/jpeg as there is imagejpeg() function but no imagejpg() $callback = 'image' . strtolower($type); // get image data ob_start(); call_user_func($callback, $this->_resource); $data = ob_get_contents(); ob_end_clean(); return $data; } /** * Check if there are image data to operate with. * * @return bool true if there has been image data set, false otherwise. */ public function hasData() { return $this->_resource !== null; } /** * Check if given image type is supported. * * @param string $type image type to check for * @return bool true if given image type is supported, false otherwise */ public static function isSupportedType($type) { $constant = 'IMG_' . strtoupper($type); return defined($constant) && (imagetypes() & constant($constant)); } /** * Scale the image to the given size. * * @param int $width the width in pixels * @param int $height the height in pixels */ protected function _scale($width = null, $height = null) { if (!$width && !$height) { throw new P4Cms_Image_Exception( 'At least one of width or height is required.' ); } // calculate original image aspect ratio $sourceWidth = $this->_getImageWidth(); $sourceHeight = $this->_getImageHeight(); $ratio = $sourceWidth / $sourceHeight; // if only one dimension is given, calculate the another one such // that new image keeps same ratio as the original if (!$width) { $width = round($height * $ratio); } else if (!$height) { $height = round($width / $ratio); } // resize the image $dst = imagecreatetruecolor($width, $height); imagecopyresized( $dst, $this->_resource, 0, 0, 0, 0, $width, $height, $sourceWidth, $sourceHeight ); $this->_resource = $dst; } /** * Sharpen the image by applying a default 3x3 matrix passed to the * imageconvolution() function. */ protected function _sharpen() { $matrix = array( array( 0.0, -1.0, 0.0), array(-1.0, 5.0, -1.0), array( 0.0, -1.0, 0.0) ); $divisor = array_sum(array_map('array_sum', $matrix)); // sharpen image by using image convolution imageconvolution( $this->_resource, $matrix, $divisor, 0 ); } /** * Crop the image to the given size and position. * * @param int|null $width the width in pixels * @param int|null $height the height in pixels * @param int $x the x coordinate starting position * @param int $y the y coordinate starting position */ protected function _crop($width = null, $height = null, $x = 0, $y = 0) { if (!$width || !$height) { throw new P4Cms_Image_Exception( 'Both width and height are required.' ); } // crop the image $dst = imagecreatetruecolor($width, $height); imagecopy( $dst, $this->_resource, 0, 0, $x, $y, $width, $height ); $this->_resource = $dst; } /** * Rotate the image. * * @param float $degrees the rotation angle */ protected function _rotate($degrees = 0) { $this->_resource = imagerotate($this->_resource, $degrees, 0); } /** * Return image width in pixels. * * @return int image width in pixels */ protected function _getImageWidth() { return imagesx($this->_resource); } /** * Return image height in pixels. * * @return int image height in pixels */ protected function _getImageHeight() { return imagesy($this->_resource); } /** * Detect image type from a given image data. * * @param string $imageData data representing image to detect type on * @return string image type (jpeg, gif etc.) * @throws P4Cms_Image_Exception if image type cannot be determined */ protected function _getType($imageData) { // try to get image type from 'finfo' if its available if (class_exists('finfo')) { $finfo = new finfo(FILEINFO_MIME_TYPE); $mime = $finfo->buffer($imageData); return str_replace('image/', '', $mime); } throw new P4Cms_Image_Exception('Cannot determine image type.'); } }