* @package chamilo.include.image * @todo move in a DB configuration setting */ class Image { public $image_wrapper = null; /** * Image constructor. * @param string $path */ public function __construct($path) { if (IMAGE_PROCESSOR == 'gd') { $this->image_wrapper = new GDWrapper($path); } else { if (class_exists('Imagick')) { $this->image_wrapper = new ImagickWrapper($path); } else { echo Display::return_message('Class Imagick not found', 'warning'); exit; } } } public function resize($max_size_for_picture) { $image_size = $this->get_image_size($this->image_wrapper->path); $width = $image_size['width']; $height = $image_size['height']; if ($width >= $height) { if ($width >= $max_size_for_picture) { // scale height $new_height = round($height * ($max_size_for_picture / $width)); $this->image_wrapper->resize($max_size_for_picture, $new_height, 0); } } else { // height > $width if ($height >= $max_size_for_picture) { // scale width $new_width = round($width * ($max_size_for_picture / $height)); $this->image_wrapper->resize($new_width, $max_size_for_picture, 0); } } } public function crop($cropParameters) { $image_size = $this->get_image_size($this->image_wrapper->path); $src_width = $image_size['width']; $src_height = $image_size['height']; $cropParameters = explode(",", $cropParameters); $x = intval($cropParameters[0]); $y = intval($cropParameters[1]); $width = intval($cropParameters[2]); $height = intval($cropParameters[3]); $image = $this->image_wrapper->crop($x, $y, $width, $height, $src_width, $src_height); return $image; } public function send_image( $file = '', $compress = -1, $convert_file_to = null ) { return $this->image_wrapper->send_image( $file, $compress, $convert_file_to ); } public function get_image_size() { return $this->image_wrapper->get_image_size(); } public function get_image_info() { return $this->image_wrapper->get_image_info(); } public function convert2bw() { $this->image_wrapper->convert2bw(); } } /** * Image wrapper class * * @package chamilo.include.image */ abstract class ImageWrapper { public $debug = true; public $path; public $width; public $height; public $type; public $allowed_extensions = array('jpeg', 'jpg', 'png', 'gif'); public $image_validated = false; public function __construct($path) { if (empty($path)) { return false; } $this->path = $path; $this->set_image_wrapper(); //Creates image obj } abstract function set_image_wrapper(); abstract function fill_image_info(); abstract function get_image_size(); abstract function resize($thumbw, $thumbh, $border, $specific_size = false); abstract function crop($x, $y, $width, $height, $src_width, $src_height); abstract function send_image($file = '', $compress = -1, $convert_file_to = null); public function get_image_info() { return array( 'width' => $this->width, 'height' => $this->height, 'type' => $this->type, ); } } /** * Imagick Chamilo wrapper * * @author jmontoya * * @package chamilo.include.image */ class ImagickWrapper extends ImageWrapper { public $image; public $filter = Imagick::FILTER_LANCZOS; /** * ImagickWrapper constructor. * @param $path */ public function __construct($path) { parent::__construct($path); } public function set_image_wrapper() { if ($this->debug) error_log('Image::set_image_wrapper loaded'); try { if (file_exists($this->path)) { $this->image = new Imagick($this->path); if ($this->image) { $this->fill_image_info(); //Fills height, width and type } } else { if ($this->debug) error_log('Image::image does not exist'); } } catch (ImagickException $e) { if ($this->debug) error_log($e->getMessage()); } } public function fill_image_info() { $image_info = $this->image->identifyImage(); $this->width = $image_info['geometry']['width']; $this->height = $image_info['geometry']['height']; $this->type = strtolower($this->image->getImageFormat()); if (in_array($this->type, $this->allowed_extensions)) { $this->image_validated = true; if ($this->debug) error_log('image_validated true'); } } public function get_image_size() { $imagesize = array('width'=>0, 'height'=>0); if ($this->image_validated) { $imagesize = $this->image->getImageGeometry(); } return $imagesize; } //@todo implement border logic case for Imagick public function resize($thumbw, $thumbh, $border, $specific_size = false) { if (!$this->image_validated) return false; if ($specific_size) { $width = $thumbw; $height = $thumbh; } else { $scale = ($this->width > 0 && $this->height > 0) ? min($thumbw / $this->width, $thumbh / $this->height) : 0; $width = (int) ($this->width * $scale); $height = (int) ($this->height * $scale); } $result = $this->image->resizeImage($width, $height, $this->filter, 1); $this->width = $thumbw; $this->height = $thumbh; } /** * @author José Loguercio * @param int $x coordinate of the cropped region top left corner * @param int $y coordinate of the cropped region top left corner * @param int $width the width of the crop * @param int $height the height of the crop * @param int $src_width the source width of the original image * @param int $src_height the source height of the original image */ public function crop($x, $y, $width, $height, $src_width, $src_height) { if (!$this->image_validated) { return false; } $this->image->cropimage($width, $height, $x, $y); $this->width = $width; $this->height = $height; } public function send_image($file = '', $compress = -1, $convert_file_to = null) { if (!$this->image_validated) { return false; } $type = $this->type; if (!empty($convert_file_to) && in_array($convert_file_to, $this->allowed_extensions)) { $type = $convert_file_to; } switch ($type) { case 'jpeg': case 'jpg': if (!$file) { header("Content-type: image/jpeg"); } break; case 'png': if (!$file) { header("Content-type: image/png"); } break; case 'gif': if (!$file) { header("Content-type: image/gif"); } break; } $result = false; try { $result = $this->image->writeImage($file); } catch (ImagickException $e) { if ($this->debug) { error_log($e->getMessage()); } } if (!$file) { echo $this->image; $this->image->clear(); $this->image->destroy(); } else { $this->image->clear(); $this->image->destroy(); return $result; } } } /** * php-gd wrapper * @package chamilo.include.image */ class GDWrapper extends ImageWrapper { public $bg; public function __construct($path) { parent::__construct($path); } public function set_image_wrapper() { $handler = null; $this->fill_image_info(); switch ($this->type) { case 0: $handler = false; break; case 1: $handler = @imagecreatefromgif($this->path); $this->type = 'gif'; break; case 2: $handler = @imagecreatefromjpeg($this->path); $this->type = 'jpg'; break; case 3: $handler = @imagecreatefrompng($this->path); $this->type = 'png'; break; } if ($handler) { $this->image_validated = true; $this->bg = $handler; @imagealphablending($this->bg, false); @imagesavealpha($this->bg, true); } } public function get_image_size() { $return_array = array('width'=>0, 'height'=>0); if ($this->image_validated) { $return_array = array('width'=>$this->width, 'height'=>$this->height); } return $return_array; } public function fill_image_info() { if (file_exists($this->path)) { $image_info = getimagesize($this->path); $this->width = $image_info[0]; $this->height = $image_info[1]; $this->type = $image_info[2]; } else { $this->width = 0; $this->height = 0; $this->type = 0; } } public function resize($thumbw, $thumbh, $border, $specific_size = false) { if (!$this->image_validated) { return false; } if ($border == 1) { if ($specific_size) { $width = $thumbw; $height = $thumbh; } else { $scale = min($thumbw / $this->width, $thumbh / $this->height); $width = (int) ($this->width * $scale); $height = (int) ($this->height * $scale); } $deltaw = (int) (($thumbw - $width) / 2); $deltah = (int) (($thumbh - $height) / 2); $dst_img = @ImageCreateTrueColor($thumbw, $thumbh); @imagealphablending($dst_img, false); @imagesavealpha($dst_img, true); if (!empty($this->color)) { @imagefill($dst_img, 0, 0, $this->color); } $this->width = $thumbw; $this->height = $thumbh; } elseif ($border == 0) { if ($specific_size) { $width = $thumbw; $height = $thumbh; } else { $scale = ($this->width > 0 && $this->height > 0) ? min($thumbw / $this->width, $thumbh / $this->height) : 0; $width = (int) ($this->width * $scale); $height = (int) ($this->height * $scale); } $deltaw = 0; $deltah = 0; $dst_img = @ImageCreateTrueColor($width, $height); @imagealphablending($dst_img, false); @imagesavealpha($dst_img, true); $this->width = $width; $this->height = $height; } $src_img = $this->bg; @ImageCopyResampled( $dst_img, $src_img, $deltaw, $deltah, 0, 0, $width, $height, ImageSX($src_img), ImageSY($src_img) ); $this->bg = $dst_img; @imagedestroy($src_img); } /** * @author José Loguercio * @param int $x coordinate of the cropped region top left corner * @param int $y coordinate of the cropped region top left corner * @param int $width the width of the crop * @param int $height the height of the crop * @param int $src_width the source width of the original image * @param int $src_height the source height of the original image */ public function crop($x, $y, $width, $height, $src_width, $src_height) { if (!$this->image_validated) { return false; } $this->width = $width; $this->height = $height; $src = null; $dest = @imagecreatetruecolor($width, $height); $type = $this->type; switch ($type) { case 'jpeg': case 'jpg': $src = @imagecreatefromjpeg($this->path); @imagecopy($dest, $src, 0, 0, $x, $y, $src_width, $src_height); @imagejpeg($dest, $this->path); break; case 'png': $src = @imagecreatefrompng($this->path); @imagecopy($dest, $src, 0, 0, $x, $y, $src_width, $src_height); @imagepng($dest, $this->path); break; case 'gif': $src = @imagecreatefromgif($this->path); @imagecopy($dest, $src, 0, 0, $x, $y, $src_width, $src_height); @imagegif($dest, $this->path); break; default: return 0; } @imagedestroy($dest); @imagedestroy($src); } public function send_image($file = '', $compress = -1, $convert_file_to = null) { if (!$this->image_validated) { return false; } $compress = (int) $compress; $type = $this->type; if (!empty($convert_file_to) && in_array($convert_file_to, $this->allowed_extensions)) { $type = $convert_file_to; } switch ($type) { case 'jpeg': case 'jpg': if (!$file) { header("Content-type: image/jpeg"); } if ($compress == -1) { $compress = 100; } return imagejpeg($this->bg, $file, $compress); break; case 'png': if (!$file) { header("Content-type: image/png"); } if ($compress != -1) { @imagetruecolortopalette($this->bg, true, $compress); } return imagepng($this->bg, $file, $compress); break; case 'gif': if (!$file) { header("Content-type: image/gif"); } if ($compress != -1) { @imagetruecolortopalette($this->bg, true, $compress); } return imagegif($this->bg, $file, $compress); break; default: return 0; } // TODO: Occupied memory is not released, because the following fragment of code is actually dead. @imagedestroy($this->bg); } /** * Convert image to black & white */ function convert2bw() { if (!$this->image_validated) { return false; } $dest_img = imagecreatetruecolor(imagesx($this->bg), imagesy($this->bg)); /* copy ignore the transparent color * so that we can use black (0,0,0) as transparent, which is what * the image is filled with when created. */ $transparent = imagecolorallocate($dest_img, 0, 0, 0); imagealphablending($dest_img, false); imagesavealpha($dest_img, true); imagecolortransparent($dest_img, $transparent); imagecopy($dest_img, $this->bg, 0, 0, 0, 0, imagesx($this->bg), imagesx($this->bg)); imagefilter($dest_img, IMG_FILTER_GRAYSCALE); $this->bg = $dest_img; return true; } }