Created
August 25, 2010 19:09
-
-
Save eberfreitas/550080 to your computer and use it in GitHub Desktop.
A simple class to handle images in PHP with GD
This file contains 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 | |
/** | |
* EasyGD - A simple class to handle images in PHP with GD | |
* | |
* Basic Usage: | |
* | |
* $image = new EasyGD('image.jpg'); | |
* $image->crop(100, 50) | |
* ->width(50) | |
* ->save('/path', 'newfile.' . $image->extension) | |
* ->display() | |
* ->end(); | |
* | |
* @author Éber Freitas Dias <[email protected]> | |
**/ | |
class EasyGD { | |
/******************************/ | |
/* GLOBALS FOR ERROR HANDLING */ | |
/******************************/ | |
const ERROR_OPEN = "It wasn't possible to open the provided image."; | |
const ERROR_SUPPORT = "This file format is not suported by EasyGD. Use a jpg or png image instead."; | |
const ERROR_RESOURCE = "There is no resource for this function. Please, run EasyGD::startFrom* to define one."; | |
const ERROR_CROP = "One of the dimensions provided are bigger than the actual image."; | |
const ERROR_ARGUMENTS = "The function was called with missing arguments."; | |
const ERROR_SERVER = "The server doesn't support this function. Please, contact you server admin."; | |
const ERROR_DISPLAY = "It wasn't possible to display the image."; | |
const ERROR_SAVE = "It wasn't possible to save the image."; | |
/**********************/ | |
/* GENERAL ATTRIBUTES */ | |
/**********************/ | |
/** | |
* @var array List of supported extensions | |
**/ | |
private $ext2mime = array( | |
'jpg' => 'image/jpeg', | |
'png' => 'image/png' | |
); | |
/** | |
* @var array List of supported mime types | |
**/ | |
private $mime2ext = array( | |
'image/jpeg' => 'jpg', | |
'image/pjpeg' => 'jpg', | |
'image/png' => 'png' | |
); | |
/** | |
* @var array List of positions for cropping. The first letter represents | |
* the X axis (Left, Center, Right) and the second letter | |
* represents the Y axis (Top, Center, Bottom) | |
**/ | |
private $positionTypes = array( | |
'LT', 'CT', 'RT', | |
'LC', 'CC', 'RC', | |
'LB', 'CB', 'RB' | |
); | |
/** | |
* @var resource Variable where the current resource will be stored | |
**/ | |
private $resource; | |
/** | |
* @var int Width of the image | |
**/ | |
private $x; | |
/** | |
* @var int Height of the image | |
**/ | |
private $y; | |
/** | |
* @var string Holds the original file name | |
**/ | |
private $filename; | |
/** | |
* @var string Extension from the current image being manipulated | |
**/ | |
private $extension; | |
/** | |
* @var array Holds the default values from the class in order to reset it | |
* properly | |
**/ | |
private $defaultVals; | |
/** | |
* @var string Holds the filename assigned by EasyGD::save | |
**/ | |
public $newFilename; | |
/** | |
* @var int This stores the image quality for JPG, from 0 to 100 | |
* (http://php.net/imagejpeg) | |
**/ | |
public $quality = 100; | |
/** | |
* @var int This stores the image compression for PNG, from 0 to 9 | |
* (http://php.net/imagepng) | |
**/ | |
public $compression = 0; | |
/****************/ | |
/* CONSTRUCTORS */ | |
/****************/ | |
public function __construct($o = null, $ext = null, $filename = null) { | |
foreach ($this as $k => $v) { | |
$this->defaultVals[$k] = $v; | |
} | |
if ($o) { | |
if (is_array($o)) { | |
return $this->startFromFile($o); | |
} | |
if (is_resource($o)) { | |
return $this->startFromResource($o, $ext, $filename); | |
} | |
if (is_string($o)) { | |
if (filter_var($o, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED)) { | |
return $this->startFromUrl($o); | |
} | |
return $this->startFromFile($o); | |
} | |
} | |
} | |
public function __destruct() { | |
$this->_reset(); | |
} | |
/*******************/ | |
/* START FUNCTIONS */ | |
/*******************/ | |
/** | |
* Use this method to start EasyGD from a file. | |
* @param string|array $file This can receive a string with the filename | |
* Ex. 'image.jpg' or an array from the $_FILES | |
* global Ex. $_FILES['myfile'] | |
**/ | |
public function startFromFile($file) { | |
if (!is_array($file)) { | |
$ext = $this->_getExtension($file); | |
if (!file_exists($file)) { | |
$this->_error(self::ERROR_OPEN); | |
} | |
if (!$this->_checkSupport(null, $ext)) { | |
$this->_error(self::ERROR_SUPPORT); | |
} | |
$this->filename = $file; | |
$this->extension = $ext; | |
} else { | |
if ($file['error'] !== 0) { | |
$this->_error(self::ERROR_OPEN); | |
} | |
if (!$this->_checkSupport($file['type'])) { | |
$this->_error(self::ERROR_SUPPORT); | |
} | |
$this->filename = $file['name']; | |
$this->extension = $this->mime2ext[$file['type']]; | |
$file = $file['tmp_name']; | |
} | |
$this->resource = $this->_create($file); | |
list($this->x, $this->y) = getimagesize($file); | |
return $this; | |
} | |
/** | |
* With this method you can start EasyGD from an already started resource | |
* @param resource $resource The image resource to be used | |
* @param string $ext The original image extension | |
* @param string $filename The original filename, not exactly necessary | |
**/ | |
public function startFromResource($resource, $ext = null, $filename = null) { | |
if (is_null($ext)) { | |
$this->_error(self::ERROR_ARGUMENTS); | |
} | |
if (!$this->_checkSupport(null, $ext)) { | |
$this->_error(self::ERROR_SUPPORT); | |
} | |
$this->resource = $resource; | |
$this->filename = !is_null($filename) ? $filename : ''; | |
$this->extension = $ext; | |
$this->x = imagesx($resource); | |
$this->y = imagesy($resource); | |
return $this; | |
} | |
/** | |
* With this method you can start EasyGD to use a remote image from a URL. | |
* @param string $url The URL of the remote image | |
**/ | |
public function startFromUrl($url) { | |
$ext = $this->_getExtension($url); | |
if (!$this->_checkSupport(null, $ext)) { | |
$this->_error(self::ERROR_SUPPORT); | |
} | |
if (function_exists('file_get_contents')) { | |
$img = file_get_contents($url); | |
} elseif (function_exists('curl_init')) { | |
$ch = curl_init(); | |
curl_setopt($ch, CURLOPT_URL, $url); | |
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); | |
$img = curl_exec($ch); | |
curl_close($ch); | |
} else { | |
$this->_error(self::ERROR_SERVER); | |
} | |
$this->resource = imagecreatefromstring($img) or $this->_error(self::ERROR_OPEN); | |
$this->filename = substr(strrchr($url, "/"), 1); | |
$this->extension = $ext; | |
$this->x = imagesx($this->resource); | |
$this->y = imagesy($this->resource); | |
return $this; | |
} | |
/******************/ | |
/* OUTPUT METHODS */ | |
/******************/ | |
/** | |
* Returns the x (width) dimension of the current image | |
**/ | |
public function x() { | |
return $this->x; | |
} | |
/** | |
* Returns the y (height) dimension of the current image | |
**/ | |
public function y() { | |
return $this->y; | |
} | |
/** | |
* Returns the image's filename, if any | |
**/ | |
public function filename() { | |
return $this->filename; | |
} | |
/** | |
* Returns image's extension | |
**/ | |
public function extension() { | |
return $this->extension; | |
} | |
/** | |
* Returns the image's resource | |
**/ | |
public function resource() { | |
return $this->resource; | |
} | |
/** | |
* This method displays the image on the browser directly | |
**/ | |
public function display() { | |
if (!$this->_checkResource()) { | |
$this->_error(self::ERROR_RESOURCE); | |
} | |
header('Content-Type: ' . $this->ext2mime[$this->extension]); | |
if ($this->_display()) { | |
return $this; | |
} | |
$this->_error(self::ERROR_DISPLAY); | |
} | |
/** | |
* This method saves the resource to an image file. You can set the path | |
* where the file will be saved as well as the file name. If none is given, | |
* the image will be saved on the current path and the file name will be | |
* automatically generated. | |
* @param string $path The path where the image will be stored or the | |
* filename you want the file to have. In this case, it | |
* will use the current path. | |
* @param string $filename The image name to be used. Ex. 'image.jpg'. Don't | |
* forget to insert the right extension. You can use | |
* EasyGD::extension to do that. | |
**/ | |
public function save($path = '', $filename = null) { | |
$hasExtension = $this->_getExtension($path); | |
if ($hasExtension) { | |
$fullPath = $path; | |
} else { | |
if (!empty($path) && $path{strlen($path)-1} !== DIRECTORY_SEPARATOR) { | |
$path = $path . DIRECTORY_SEPARATOR; | |
} | |
if (is_null($filename)) { | |
$filename = time() . "." . $this->extension; | |
} | |
$this->newFilename = $filename; | |
$fullPath = $path . $filename; | |
} | |
if ($this->_display($fullPath)) { | |
return $this; | |
} | |
$this->_error(self::ERROR_SAVE); | |
} | |
/**********************/ | |
/* ADJUSTMENT METHODS */ | |
/**********************/ | |
/** | |
* If you are using transparent PNG images you might want to activate its | |
* alpha channel. That is what this method do. | |
**/ | |
public function setAlpha() { | |
if ($this->extension === 'png') { | |
imagealphablending($this->resource, false); | |
imagesavealpha($this->resource, true); | |
} | |
return $this; | |
} | |
/************************/ | |
/* MANIPULATION METHODS */ | |
/************************/ | |
/** | |
* Method to resize an image | |
* @param int $width Width to be resized | |
* @param int $height Height to be resized | |
**/ | |
public function resize($width, $height) { | |
if (!$this->_checkResource()) { | |
$this->_error(self::ERROR_RESOURCE); | |
} | |
$newResource = imagecreatetruecolor($width, $height); | |
imagecopyresampled( | |
$newResource, | |
$this->resource, | |
0, 0, 0, 0, | |
$width, $height, $this->x, $this->y | |
); | |
$this->startFromResource($newResource, $this->extension, $this->filename); | |
return $this; | |
} | |
/** | |
* Shortcut for the EasyGD::resize function where you can set a with and the | |
* height is calculated proportionally | |
* @param int $width New image width to be resized | |
* @param bool $force If false, returns the original image if the new width | |
* is larger than the original | |
**/ | |
public function width($width, $force = true) { | |
if ($force === true || $width < $this->x) { | |
return $this->resize($width, round(($this->y / $this->x) * $width)); | |
} else { | |
return $this; | |
} | |
} | |
/** | |
* Shortcut for the EasyGD::resize function where you can set a height and | |
* the width is calculated proportionally | |
* @param int $height New image height to be resized | |
* @param bool $force If false, returns the original image if the new height | |
* is larger than the original | |
**/ | |
public function height($height, $force = true) { | |
if ($force === true || $height < $this->y) { | |
return $this->resize(round(($this->x / $this->y) * $height), $height); | |
} else { | |
return $this; | |
} | |
} | |
/** | |
* Method where you can crop an image. You can use the pre-defined patterns | |
* with $type or define your own position with $x and $y | |
* @param int $width Width of the crop | |
* @param int $height Height of the crop | |
* @param string $type One of the EasyGD::positionTypes | |
* @param int $x The X axis to start the crop | |
* @param int $y The Y axis to start the crop | |
* @param bool $force If the crop size is larger than the original image and | |
* $force === true, it will resize the image and then | |
* crop it | |
*/ | |
public function crop($width, $height, $type = 'CC', $x = null, $y = null, $force = false) { | |
if (!$this->_checkResource()) { | |
$this->_error(self::ERROR_RESOURCE); | |
} | |
if (($force === false) && ($width > $this->x || $height > $this->y)) { | |
$this->_error(self::ERROR_CROP); | |
} | |
if ($width > $this->x || $height > $this->y) { | |
$max = max($width, $height); | |
if ($this->x > $this->y) { | |
$this->height($max); | |
} else { | |
$this->width($max); | |
} | |
} | |
if (!in_array($type, $this->positionTypes) || is_null($type)) { | |
$type = 'CC'; | |
} | |
if (is_null($x) || is_null($y)) { | |
$axis = $this->_calcPosition($type, $this->x, $this->y, $width, $height); | |
extract($axis); | |
} else { | |
$leftX = $this->x - $width; | |
$leftY = $this->y - $height; | |
if ($x + $width > $this->x) { | |
$x = $leftX; | |
} | |
if ($y + $height > $this->y) { | |
$y = $leftY; | |
} | |
} | |
$newResource = imagecreatetruecolor($width, $height); | |
imagecopy($newResource, $this->resource, 0, 0, $x, $y, $this->x, $this->y); | |
$this->startFromResource($newResource, $this->extension, $this->filename); | |
return $this; | |
} | |
/** | |
* This will destroy the current resource and reset the variables so you can | |
* start it all over again! :) | |
**/ | |
public function end() { | |
return $this->_reset(); | |
} | |
/*********************/ | |
/* EDITION FUNCTIONS */ | |
/*********************/ | |
/** | |
* This method will place a watermark on the current working image. | |
* @param string $file Path to the file being used as a watermark | |
* @param string $type One of the EasyGD::positionTypes | |
* @param int $padding The padding in pixels | |
* @param int|bool $alpha Sets the transparency level of the watermark or | |
* preserve PNG transparency if set to 'true' | |
**/ | |
public function placeWatermark($file = '', $type = 'RB', $padding = 10, $alpha = 100) { | |
if (!in_array($type, $this->positionTypes) || is_null($type)) { | |
$type = 'RB'; | |
} | |
$ext = $this->_getExtension($file); | |
$function = $this->_getFunction($ext); | |
$wmResource = $function['create']($file); | |
if ($ext === 'png' && $alpha === true) { | |
imagealphablending($wmResource, false); | |
imagesavealpha($wmResource, true); | |
} | |
$wmWidth = imagesx($wmResource); | |
$wmHeight = imagesy($wmResource); | |
$newResource = imagecreatetruecolor($this->x, $this->y); | |
imagecopyresampled( | |
$newResource, | |
$this->resource, | |
0, 0, 0, 0, | |
$this->x, $this->y, $this->x, $this->y | |
); | |
$axis = $this->_calcPosition( | |
$type, | |
$this->x, $this->y, | |
$wmWidth, $wmHeight, | |
$padding | |
); | |
if ($alpha === true) { | |
imagecopy( | |
$newResource, | |
$wmResource, | |
$axis['x'], $axis['y'], | |
0, 0, | |
$wmWidth, $wmHeight | |
); | |
} else { | |
imagecopymerge( | |
$newResource, | |
$wmResource, | |
$axis['x'], $axis['y'], | |
0, 0, | |
$wmWidth, $wmHeight, | |
$alpha | |
); | |
} | |
$this->startFromResource($newResource, $this->extension, $this->filename); | |
imagedestroy($wmResource); | |
return $this; | |
} | |
/********************/ | |
/* INTERNAL METHODS */ | |
/********************/ | |
private function _calcPosition($type = 'CC', $x, $y, $width, $height, $padding = false) { | |
$leftX = $x - $width; | |
$leftY = $y - $height; | |
$return = array(); | |
switch ($type) { | |
case "LT": | |
$return['x'] = $return['y'] = ($padding) ? $padding : 0; | |
break; | |
case "CT": | |
$return['x'] = round($leftX / 2); | |
$return['y'] = ($padding) ? $padding : 0; | |
break; | |
case "RT": | |
$return['x'] = ($padding) ? $leftX - $padding : $leftX; | |
$return['y'] = ($padding) ? $padding : 0; | |
break; | |
case "LC": | |
$return['x'] = ($padding) ? $padding : 0; | |
$return['y'] = round($leftY / 2); | |
break; | |
case "CC": | |
$return['x'] = round($leftX / 2); | |
$return['y'] = round($leftY / 2); | |
break; | |
case "RC": | |
$return['x'] = ($padding) ? $leftX - $padding : $leftX; | |
$return['y'] = round($leftY / 2); | |
break; | |
case "LB": | |
$return['x'] = ($padding) ? $padding : 0; | |
$return['y'] = ($padding) ? $leftY - $padding : $leftY; | |
break; | |
case "CB": | |
$return['x'] = round($leftX / 2); | |
$return['y'] = ($padding) ? $leftY - $padding : $leftY; | |
break; | |
case "RB": | |
$return['x'] = ($padding) ? $leftX - $padding : $leftX; | |
$return['y'] = ($padding) ? $leftY - $padding : $leftY; | |
break; | |
} | |
return $return; | |
} | |
private function _checkResource() { | |
return gettype($this->resource) === 'resource'; | |
} | |
private function _checkSupport($mime = null, $ext = null) { | |
if (!is_null($mime)) { | |
$mimes = array_keys($this->mime2ext); | |
return in_array($mime, $mimes); | |
} elseif (!is_null($ext)) { | |
return in_array($ext, $this->mime2ext); | |
} | |
return false; | |
} | |
private function _create($file) { | |
switch ($this->extension) { | |
case 'jpg': | |
return imagecreatefromjpeg($file); | |
break; | |
case 'png': | |
return imagecreatefrompng($file); | |
break; | |
} | |
} | |
private function _display($path = null) { | |
switch ($this->extension) { | |
case 'jpg': | |
$quality = ($this->quality > 100 || $this->quality < 0) | |
? 100 : $this->quality; | |
return imagejpeg($this->resource, $path, $quality); | |
break; | |
case 'png': | |
$compression = ($this->compression > 9 || $this->compression < 0) | |
? 9 : $this->compression; | |
return imagepng($this->resource, $path, $compression); | |
break; | |
} | |
} | |
private function _getExtension($file) { | |
$file = basename($file); | |
return strtolower(substr(strrchr($file, "."), 1)); | |
} | |
private function _reset() { | |
if ($this->_checkResource()) { | |
imagedestroy($this->resource); | |
} | |
foreach ($this as $k => $v) { | |
$this->{$k} = isset($this->defaultVals[$k]) ? $this->defaultVals[$k] : null; | |
} | |
return true; | |
} | |
private function _error($msg) { | |
$this->_reset(); | |
throw new Exception($msg); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment