Created
September 27, 2017 04:13
-
-
Save odahcam/e7255f406e02ddf390080bf3add2cd43 to your computer and use it in GitHub Desktop.
A PHP class to wrap imageGD PHP library into a OO class.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @version 0.2.0 | |
*/ | |
class ImageGD | |
{ | |
public $image_src; // the source of the image | |
public $src_image; // the source image | |
public $image; // the modified (or not) image | |
public $written_path; // the path of first write execution | |
public $last_written_path; // the path of last write execution | |
public $width; | |
public $height; | |
public $watermark_src; // the source of the image used to watermark $image | |
public $extension; // the source image extension | |
public $mime_type; // the source image mime type | |
private $image_create_function_name; | |
private $image_write_function_name; | |
/** | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @param string $image_src The path/url to the image | |
* | |
* @return void | |
*/ | |
public function __construct(string $image_src) | |
{ | |
try { | |
$this->type = exif_imagetype($image_src); | |
} catch (Exception $e) { | |
throw new \Exception('Erro fatal na recuperação dos dados da imagem: '.$e->getMessage(), 1); | |
} | |
if ((bool) $this->type) { | |
$this->extension = image_type_to_extension($this->type, false); // false == sem . (ponto) na extensão | |
$this->mime_type = image_type_to_mime_type($this->type); | |
$this->image_create_function_name = 'imagecreatefrom'.$this->extension; | |
$this->image_write_function_name = 'image'.$this->extension; | |
$new_image = $this->image_create($image_src); | |
if ($new_image !== false) { | |
$this->image_src = $image_src; | |
$this->src_image = $new_image; | |
$this->image = $this->src_image; | |
$this->width = imagesx($this->image); | |
$this->height = imagesy($this->image); | |
if ($this->extension == 'gif' || $this->extension == 'png') { | |
$this->resize(); // ajusta a camada transparente da imagem para não ficar com fundo negro | |
} | |
unset($new_image); | |
return; // success | |
} | |
} | |
$this->src_image = null; | |
$this->image = null; | |
} | |
/** | |
* @author odahcam | |
* | |
* @method __destruct | |
* Destruct protocols to execute on object destruction | |
**/ | |
public function __destruct() | |
{ | |
if (is_resource($this->image)) { | |
imagedestroy($this->image); | |
} | |
if (is_resource($this->src_image)) { | |
imagedestroy($this->src_image); | |
} | |
} | |
/** | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @param string $image_src | |
* | |
* @return Object ImageGD | |
*/ | |
public static function from(string $image_src) | |
{ | |
return new self($image_src); | |
} | |
/** | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* @author Alex | |
* | |
* @source http://stackoverflow.com/a/3677986/4367683 | |
* | |
* @param string $url | |
* | |
* @return boolean If the URL exists or not | |
*/ | |
public static function image_exists(string $url = null) | |
{ | |
// This method doesn't work properly. | |
$headers = get_headers($url); | |
return is_array($headers) ? preg_match('/^HTTP\\/\\d+\\.\\d+\\s+2\\d\\d\\s+.*$/', $headers[0]) : false; | |
} | |
/** | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @param string $filename | |
* | |
* @return mixed $this Object or (bool) False | |
*/ | |
private function image_create(string $filename) | |
{ | |
return call_user_func($this->image_create_function_name, $filename); | |
} | |
/** | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @param resource $image | |
* @param string $filename | |
* @param int $quality | |
* @param int $mode | |
* | |
* @return Object $this | |
* @return bool false | |
*/ | |
private function image_write($image, string $filename = null, int $quality = null, $mode = 0755) | |
{ | |
$this->written_path = $this->written_path ?: $filename; // first write execution | |
$this->last_written_path = $filename; // last write execution | |
return call_user_func($this->image_write_function_name, $image, $filename, $quality); | |
/* | |
$dir = pathinfo($filename, PATHINFO_DIRNAME); | |
if (self::makedirs($dir, $mode)) { | |
return call_user_func($this->image_write_function_name, $image, $filename, $quality); | |
} else { | |
throw new \Exception("Não foi possível criar/adicionar permissões ao diretório desejado."); | |
return false; | |
} | |
*/ | |
} | |
/** | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @param string $to | |
* @param int $quality | |
* @param int $mode | |
* | |
* @return Object $this | |
* @return bool false | |
*/ | |
public function write(string $to = null, $quality = 90, $mode = 0775) | |
{ | |
$quality = intval($this->extension == 'png' ? $quality / 10 : $quality); | |
if ($this->image_write($this->image, ($to ?: $this->image_src), $quality, $mode) !== false) { | |
return $this; | |
} else { | |
throw new \Exception('Não foi possível escrever a imagem para '.($to ?: $this->image_src).'.', 1); | |
return false; | |
} | |
} | |
/** | |
* Erases the last written image. Erases the first written image if $first == true. | |
* | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @param bool $first | |
* | |
* @return bool | |
**/ | |
public function erase($first = false) | |
{ | |
if (unlink(($first) ? $this->written_path : $this->last_written_path)) { | |
return $this; | |
} else { | |
return false; | |
} | |
} | |
/** | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @return Object ImageGD | |
**/ | |
public function reset() | |
{ | |
$this->image = $this->src_image; | |
$this->width = imagesx($this->src_image); | |
$this->height = imagesy($this->src_image); | |
return $this; | |
} | |
/** | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @param int $w | |
* @param int $h | |
* @param bool $to_crop | |
* | |
* @return Object $this | |
*/ | |
public function resize(int $w = null, int $h = null, $to_crop = false) | |
{ | |
$crop = $resize = $src = [ // define os valores padrões | |
'width' => $this->width, | |
'height' => $this->height, | |
'position' => [ | |
'x' => 0, | |
'y' => 0, | |
], | |
]; | |
if (!(empty($w) && empty($h))) { // verifica se um tamanho foi solicitado | |
$w = $w ?: $h; // corrige o tamanho de largura e altura | |
$h = $h ?: $w; // para que as variáveis não fiquem nulas | |
$scale_select = ($to_crop) ? 'max' : 'min'; | |
$scale = $scale_select($w / $src['width'], $h / $src['height']); | |
$resize['width'] = $crop['width'] = floor($scale * $src['width']); | |
$resize['height'] = $crop['height'] = floor($scale * $src['height']); | |
if ($to_crop) { | |
$crop = [ | |
'width' => $w, | |
'height' => $h, | |
'position' => [ | |
'x' => $resize['width'] - $w, | |
'y' => $resize['height'] - $h, | |
], | |
]; | |
} | |
} | |
// $dst === destination | |
$dst = imagecreatetruecolor($crop['width'], $crop['height']); // png ?: gif | |
switch ($this->extension) { | |
case 'gif': | |
case 'png': | |
// integer representation of the color black (rgb: 0,0,0) | |
$background = imagecolorallocate($dst, 0, 0, 0); | |
// removing the black from the placeholder | |
imagecolortransparent($dst, $background); | |
// no break | |
case 'gif': | |
if (self::is_animated($this->image)) { | |
// @TODO split frames and resize to keep animation | |
} | |
// no break | |
case 'png': | |
// turning off alpha blending (to ensure alpha channel information | |
// is preserved, rather than removed (blending with the rest of the | |
// image in the form of black)) | |
imagealphablending($dst, false); | |
// turning on alpha channel information saving (to ensure the full range | |
// of transparency is preserved) | |
imagesavealpha($dst, true); | |
break; | |
default: | |
break; | |
} | |
$old_max_time = ini_get('max_execution_time'); | |
set_time_limit(900); | |
imagecopyresampled($dst, $this->image, $resize['position']['x'], $resize['position']['y'], $crop['position']['x'], $crop['position']['y'], $resize['width'], $resize['height'], $src['width'], $src['height']); // se o png tiver + de 0% de opacidade no canal alpha, então ele ficará preto | |
set_time_limit($old_max_time); | |
// imagedestroy($this->image); | |
$this->image = $dst; | |
$this->width = $crop['width']; | |
$this->height = $crop['height']; | |
return $this; | |
} | |
/** | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @param string $watermark_src | |
* @param int $size in % | |
* @param int $margin_right in px | |
* @param int $margin_bottom in px | |
* | |
* @return Object $this | |
*/ | |
public function watermark(string $watermark_src, $size = 26, $margin_right = 25, $margin_bottom = 25) | |
{ | |
$stamp = self::from($watermark_src)->resize($size / 100 * $this->width); // resize by 26% width of $this->image | |
unset($watermark_src); | |
// Copy the $stamp image onto our $this->image using the margin offsets and the photo width to calculate positioning of the stamp. | |
imagecopy($this->image, $stamp->image, $this->width - $stamp->width - $margin_right, $this->height - $stamp->height - $margin_bottom, 0, 0, $stamp->width, $stamp->height); | |
// $this->image_write($this->image, $this->src_image, 70); | |
return $this; | |
} | |
/** | |
* @author odahcam | |
* @source http://it2.php.net/manual/en/function.imagecreatefromgif.php#59787 | |
* | |
* @param string $filename | |
**/ | |
public static function is_animated(string $filename) | |
{ | |
$filecontents = file_get_contents($filename); | |
$str_loc = 0; | |
$count = 0; | |
while ($count < 2) { // There is no point in continuing after we find a 2nd frame | |
$where1 = strpos($filecontents, "\x00\x21\xF9\x04", $str_loc); | |
if (!$where1) { | |
break; | |
} else { | |
$str_loc = $where1 + 1; | |
$where2 = strpos($filecontents, "\x00\x2C", $str_loc); | |
if (!$where2) { | |
break; | |
} else { | |
if ($where1 + 8 == $where2) { | |
++$count; | |
} | |
$str_loc = $where2 + 1; | |
} | |
} | |
} | |
return $count > 1; | |
} | |
/** | |
* Imprime a imagem no documento. | |
* | |
* @author Luiz Filipe Machado Barni <[email protected]> | |
* | |
* @param void | |
* | |
* @return Object $this | |
*/ | |
public function dump() | |
{ | |
header('Content-type: '.$this->mime_type); | |
$this->write(); | |
return $this; | |
} | |
/** | |
* Create directory if not exists. | |
* | |
* @param string $dirpath | |
* @param int $mode | |
* @param bool $recursive | |
* | |
* @return bool | |
*/ | |
public static function makedirs(string $dirpath, $mode = 0755, $recursive = true) | |
{ | |
//$old = umask(002); | |
$status = is_dir($dirpath) || mkdir($dirpath, $mode, $recursive); | |
$status = ($status) ? @chmod($dirpath, 0755) : false; // use without umask() | |
//umask($old); | |
return $status; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment