Skip to content

Instantly share code, notes, and snippets.

@odahcam
Created September 27, 2017 04:13
Show Gist options
  • Save odahcam/e7255f406e02ddf390080bf3add2cd43 to your computer and use it in GitHub Desktop.
Save odahcam/e7255f406e02ddf390080bf3add2cd43 to your computer and use it in GitHub Desktop.
A PHP class to wrap imageGD PHP library into a OO class.
<?php
/**
* @author Luiz Filipe Machado Barni <luiz@h2k.com.br>
*
* @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 <luiz@h2k.com.br>
*
* @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 <luiz@h2k.com.br>
*
* @param string $image_src
*
* @return Object ImageGD
*/
public static function from(string $image_src)
{
return new self($image_src);
}
/**
* @author Luiz Filipe Machado Barni <luiz@h2k.com.br>
* @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 <luiz@h2k.com.br>
*
* @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 <luiz@h2k.com.br>
*
* @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 <luiz@h2k.com.br>
*
* @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 <luiz@h2k.com.br>
*
* @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 <luiz@h2k.com.br>
*
* @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 <luiz@h2k.com.br>
*
* @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 <luiz@h2k.com.br>
*
* @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 <luiz@h2k.com.br>
*
* @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