diff --git a/README.md b/README.md index 2f97eee..7a5fe5c 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,58 @@ ### Summary and features Really flexible and easy-to-use PHP class to work with images using the GD Library +Included Layer Effects. + http://phpimageworkshop.com/ ### Latest updates +**Version 2.0.8.1 - 2014-5-6** +- Updated includeds to allow load files if the main class is not already defined (like autoloading except), if you still wish to auto load (inorder to add custom load files) then just comment out +```php + + if (!class_exists('classname')) { + require_once(pathandfilename.php'); +} + +// example : +if (!class_exists('ImageWorkshopLayer')) { // auto loads if not already loaded. + require_once(__DIR__.'/Core/ImageWorkshopLayer.php'); +} + +``` + + +**Version 2.0.8 - 2014-5-6** +- removed Layer Effect class and merged back into main Layer Class(Working to resolve issues with extracted effects). +- add new enableAlpha method: the first argument turns on alpha blending for graphic manipuation, the second turns on alpha blending when saving image (this prevents the black background). +- add new setTransparentColor method: the first three arguments are RBG values of the color the forth is the tolerance so colors +/- the tolerance will also be made transparent the fifth argument is optional and it locks the tolerance so that only color with the same hue and saturation as the base color will be altered, optional feather by tolerance true/false is the sixth argument. this cause the degree of transpanancy to Decay futher the color differs from the base color. +```php + + $layer->enabeAlpha($blend,$save); + example: + $layer->enabeAlpha(true,true); + + $layer->setTransparentColor($r,$g,$b,$tolerance,$Lock,$feather); + example: + $layer->setTransparentColor(0,0,0,7,false,true); +``` + +**Version 2.0.7 - 2014-3-6** + +- Move Layer effect into there own class, allowing you to use your own effects libaries. + +- Added Extended_Effects method which request Effect name, EffectsLib object , and if it should apply recursively. + +**Version 2.0.7 - 2014-2-5** +- Forked +- Added Layer Effect: + - applyFilter + - applyImageConvolution + - toGreyscale + - applyAlphaMask + - splitChannels + - getChannel + - mergeChannels **Version 2.0.5 - 2013-11-12** @@ -95,4 +144,4 @@ The class is designed for PHP 5.3+, but it can work with older PHP versions... C ### @todo - Adding a method to add easily borders to a layer (external, inside and middle border) -- Check given hexa' color and remove # if exists. \ No newline at end of file +- Check given hexa' color and remove # if exists. diff --git a/src/PHPImageWorkshop/Core/Exception/ImageWorkshopLayerException.php b/src/PHPImageWorkshop/Core/Exception/ImageWorkshopLayerException.php index 6628b4d..820301b 100644 --- a/src/PHPImageWorkshop/Core/Exception/ImageWorkshopLayerException.php +++ b/src/PHPImageWorkshop/Core/Exception/ImageWorkshopLayerException.php @@ -5,7 +5,11 @@ use PHPImageWorkshop\Exception\ImageWorkshopBaseException as ImageWorkshopBaseException; // If no autoloader, uncomment these lines: -//require_once(__DIR__.'/../../Exception/ImageWorkshopBaseException.php'); + +if (!class_exists('ImageWorkshopBaseException')) { // auto loads if not already loaded. + require_once(__DIR__.'/../../Exception/ImageWorkshopBaseException.php'); +} + /** * ImageWorkshopLayerException diff --git a/src/PHPImageWorkshop/Core/Exception/ImageWorkshopLibException.php b/src/PHPImageWorkshop/Core/Exception/ImageWorkshopLibException.php index 18338f9..814117f 100644 --- a/src/PHPImageWorkshop/Core/Exception/ImageWorkshopLibException.php +++ b/src/PHPImageWorkshop/Core/Exception/ImageWorkshopLibException.php @@ -5,7 +5,11 @@ use PHPImageWorkshop\Exception\ImageWorkshopBaseException as ImageWorkshopBaseException; // If no autoloader, uncomment these lines: -//require_once(__DIR__.'/../../Exception/ImageWorkshopBaseException.php'); + +if (!class_exists('ImageWorkshopBaseException')) { + require_once(__DIR__.'/../../Exception/ImageWorkshopBaseException.php'); +} + /** * ImageWorkshopLibException diff --git a/src/PHPImageWorkshop/Core/ImageWorkshopLayer.php b/src/PHPImageWorkshop/Core/ImageWorkshopLayer.php index 37944fd..3117e12 100644 --- a/src/PHPImageWorkshop/Core/ImageWorkshopLayer.php +++ b/src/PHPImageWorkshop/Core/ImageWorkshopLayer.php @@ -7,9 +7,22 @@ use PHPImageWorkshop\Core\Exception\ImageWorkshopLayerException as ImageWorkshopLayerException; // If no autoloader, uncomment these lines: -//require_once(__DIR__.'/../ImageWorkshop.php'); -//require_once(__DIR__.'/ImageWorkshopLib.php'); -//require_once(__DIR__.'/Exception/ImageWorkshopLayerException.php'); +if (!class_exists('ImageWorkshop') and !isset($autoload)) { // auto loads if not already loaded. + require_once(__DIR__.'/../ImageWorkshop.php'); +} + +if (!class_exists('ImageWorkshopLib') and !isset($autoload)) { // auto loads if not already loaded. + require_once(__DIR__.'/ImageWorkshopLib.php'); +} + +if (!class_exists('ImageWorkshopLayerException') and !isset($autoload)) { // auto loads if not already loaded. + require_once(__DIR__.'/Exception/ImageWorkshopLayerException.php'); +} + + + + + /** * ImageWorkshopLayer class @@ -21,6 +34,9 @@ * @license http://en.wikipedia.org/wiki/MIT_License * @copyright Clément Guillemain */ + + + class ImageWorkshopLayer { // =================================================================================== @@ -119,6 +135,18 @@ class ImageWorkshopLayer * @var integer */ const ERROR_NEGATIVE_NUMBER_USED = 5; + + /** + * @var integer + */ + const ERROR_LAYER_GROUP = 6; + + /** + * @var integer + */ + const ERROR_IMAGE_TYPE = 7; + + // =================================================================================== // Methods @@ -1185,6 +1213,56 @@ public function opacity($opacity, $recursive = true) unset($transparentImage); } + /** + * Enable Alpha + * enable alpha blending and enable saving of the alpha channel. + * + * @param boolen $enable - true enables alpha blending + * @param boolen $save - true enables saving of the alpha channel. + */ + + public function enableAlpha($enable = true,$save = true){ + imageAlphaBlending($this->image, $enable); + imageSaveAlpha($this->image, $save); + } + + /** + * Set TransparentColor + * makes a color transparent even if the image already has + * + * @param int $filterType (http://www.php.net/manual/en/function.imagefilter.php) + * @param int $r,$g,$b - color value for the color that is to be made transparent + * @param int $t - tolerance (color that are close to the color that is to be made transparent will also be made transparent) + * @param int $f - feather (color that are close will be made transparent by the degree that that are close to the color). + * @param int $L - lock luminissity (color are only considered clode if they have the same hue and saturation as the request color). + * @param boolean $recursive + */ + public function setTransparentColor($r=0,$b=0,$g=0,$t=0,$L = true,$f=false){ + if(!imageistruecolor($this->image)){ throw new ImageWorkshopException('Can\'t set a color to transparent Image is not true color', static::ERROR_IMAGE_TYPE);} + + for ($h=0; $h<$this->height; $h++){ + for ($w=0; $w<$this->width; $w++){ + $rgb = imagecolorat($this->image, $w, $h); + $Cr = ($rgb >> 16) & 0xFF; + $Cg = ($rgb >> 8) & 0xFF; + $Cb = $rgb & 0xFF; + $alpha = 127; + + + if($Cr<$r+$t and $Cr>$r-$t and $Cg<$g+$t and $Cg>$g-$t and $Cb<$b+$t and $Cb>$b-$t or $Cr==$r and $Cg==$g and $Cb==$b){// color comparason + if($Cr-$r == $Cg>$g and $Cg-$g == $Cb>$b or $L == false){// brightness lock + if($f==true){// Feathering + $alpha = 127-(127/$t)*($Cr-$r); + } + + imagesetpixel($this->image,$w,$h,imagecolorallocatealpha($this->image,$r,$g,$b,$alpha)); + } + } + + } + } + } + /** * Apply a filter on the layer * Be careful: some filters can damage transparent images, use it sparingly ! (A good pratice is to use mergeAll on your layer before applying a filter) @@ -1217,7 +1295,309 @@ public function applyFilter($filterType, $arg1 = null, $arg2 = null, $arg3 = nul } } } - + + /** + * Apply a image convolution on the layer + * + * + * @param array $matrix + * @param int $div + * @param int $offset + * @param boolean $recursive + * + * @author Email Goodlittledeveloper@gmail.com + * + */ + public function applyImageConvolution($matrix, $div=0, $offset=0,$recursive=false){ + if(is_string($matrix)){ + $matrix = strtolower($matrix); + switch($matrix){ + case "blur": + $matrix = array(array(1,1,1), array(1,.25,1), array(1,1,1)); + $div = 8.25; + $offset = 0; + break; + + case "emboss": + $matrix = array(array(2, 2, 2), array(2, 1, -2), array(-2, -2, -2)); + $div = 0; + $offset = 127; + break; + + case "gaussian blur" : + $matrix = array(array(1.0, 2.0, 1.0), array(2.0, 4.0, 2.0), array(1.0, 2.0, 1.0)); + $div = 16; + $offset = 0; + break; + + case "sharpen" : + $Matrix = array(array(-1.2, -1.2, -1.2),array(-1.2, .4, -1.2),array(-1.2, -1.2, -1.2)); + $div = array_sum(array_map('array_sum', $Matrix)); + $offset = 0; + break; + + } + + } + if(is_array($matrix)){ + imageconvolution($this->image, $matrix, $div, $offset); + } + + if ($recursive) { + + $layers = $this->layers; + + foreach($layers as $layerId => $layer) { + $this->layers[$layerId]->applyImageConvolution($matrix, $div, $offset, true); + } + } + + + + } + + public function toGreyscale($type = null,$recursive=false){ + $type = strtolower($type); + + switch ($type) { + case 'lightness': + for ($h=0; $h<$this->height; $h++){ + for ($w=0; $w<$this->width; $w++){ + $rgb = imagecolorat($this->image, $w, $h); + $r = ($rgb >> 16) & 0xFF; + $g = ($rgb >> 8) & 0xFF; + $b = $rgb & 0xFF; + $a = ($rgb & 0x7F000000) >> 24; + + $grey = (max($r,$g,$b)+min($r,$g,$b))/2; + + imagesetpixel($this->image,$w,$h,imagecolorallocatealpha($this->image,$grey,$grey,$grey,$a)); + } + } + + break; + + case 'luminosity': + for ($h=0; $h<$this->height; $h++){ + for ($w=0; $w<$this->width; $w++){ + $rgb = imagecolorat($this->image, $w, $h); + $r = ($rgb >> 16) & 0xFF; + $g = ($rgb >> 8) & 0xFF; + $b = $rgb & 0xFF; + $a = ($rgb & 0x7F000000) >> 24; + + $grey = 0.21*$r+0.71*$g+0.07*$b; + + imagesetpixel($this->image,$w,$h,imagecolorallocatealpha($this->image,$grey,$grey,$grey,$a)); + } + } + break; + + default://average + for ($h=0; $h<$this->height; $h++){ + for ($w=0; $w<$this->width; $w++){ + $rgb = imagecolorat($this->image, $w, $h); + $r = ($rgb >> 16) & 0xFF; + $g = ($rgb >> 8) & 0xFF; + $b = $rgb & 0xFF; + $a = ($rgb & 0x7F000000) >> 24; + + $grey = ($r+$g+$b)/3; + + imagesetpixel($this->image,$w,$h,imagecolorallocatealpha($this->image,$grey,$grey,$grey,$a)); + } + } + break; + } + + if ($recursive) { + + $layers = $this->layers; + + foreach($layers as $layerId => $layer) { + $this->layers[$layerId]->toGreyscale($type, true); + } + } + } + + /** + * Apply alpha layer mask. + * + * @param layer $mask + * + * @author email goodlittledeveloper@gmail.com + * + */ + + public function applyAlphaMask($mask){ + + $masktemp = clone $mask; + + $masktemp->resizeInPixel($this->width, $this->height); // make $mask and $layer the same size. + $masktemp->applyFilter(IMG_FILTER_GRAYSCALE); //converts to greyscale if not greyscale; + $masktemp->applyFilter(IMG_FILTER_NEGATE); // inverts the mask so black = 100% transparent and white = 0 + + $layerImg= $this->getImage(); + $maskImg = $masktemp->getImage(); + + $imgtemp = imageCreateTrueColor($this->width,$this->height); + + imagealphablending($imgtemp, false); + imagesavealpha($imgtemp, true); + + + for ($h=0; $h<$this->height; $h++){ + for ($w=0; $w<$this->width; $w++){ + $Lrgb = imagecolorat($layerImg, $w, $h); + $Lcolors = imagecolorsforindex($layerImg, $Lrgb); + + + $alpha = (imagecolorat($maskImg, $w, $h) >> 16) & 0xFF; //faster calc to get red value. + $alpha = $alpha/255*127; // the gets alpha from red value + + imagesetpixel($imgtemp,$w,$h,imagecolorallocatealpha($imgtemp,$Lcolors["red"],$Lcolors["green"],$Lcolors["blue"],$alpha)); + }} + + + + + unset($this->image); + $this->image = $imgtemp; + unset($imgtemp); + + } + + /** + * split Layer in to channels. + * + * @return a group of 4 layers each one a channel. + * + * @author email goodlittledeveloper@gmail.com + * + */ + + public function splitChannels(){ + if($this->getLastLayerId()!=0){ + throw new ImageWorkshopException('Can\'t split channels of a layer group', static::ERROR_LAYER_GROUP); + } + else{ + + $ChlR = imageCreateTrueColor($this->width,$this->height); + $ChlG = imageCreateTrueColor($this->width,$this->height); + $ChlB = imageCreateTrueColor($this->width,$this->height); + $ChlA = imageCreateTrueColor($this->width,$this->height); + + for ($h=0; $h<$this->height; $h++){ + for ($w=0; $w<$this->width; $w++){ + $Lrgb = imagecolorat($this->image, $w, $h); + $Lcolors = imagecolorsforindex($this->image, $Lrgb); + + + imagesetpixel($ChlR,$w,$h,imagecolorallocatealpha($ChlR,$Lcolors["red"],0,0,0)); + imagesetpixel($ChlG,$w,$h,imagecolorallocatealpha($ChlG,0,$Lcolors["green"],0,0)); + imagesetpixel($ChlB,$w,$h,imagecolorallocatealpha($ChlB,0,0,$Lcolors["blue"],0)); + imagesetpixel($ChlA,$w,$h,imagecolorallocatealpha($ChlA,127,127,127,$Lcolors["alpha"])); + }} + + $group = ImageWorkshop::initVirginLayer($this->width,$this->height); + $r = ImageWorkshop::initFromResourceVar($ChlR); + $g = ImageWorkshop::initFromResourceVar($ChlG); + $b = ImageWorkshop::initFromResourceVar($ChlB); + $a = ImageWorkshop::initFromResourceVar($ChlA); + + unset($ChlR); + unset($ChlG); + unset($ChlB); + unset($ChlA); + + + $sublayerInfos = $group->addLayer("1", $r, 0, 0, "LT"); + $sublayerInfos = $group->addLayer("2", $g, 0, 0, "LT"); + $sublayerInfos = $group->addLayer("3", $b, 0, 0, "LT"); + $sublayerInfos = $group->addLayer("4", $a, 0, 0, "LT"); + + return $group; + }} + + /** + * get channel by color. + * + * @param string of channel name + * + * @return a layer based on channel name a channel. + * + * @author email goodlittledeveloper@gmail.com + * + */ + + public function getChannel($channel){ + switch ($channel) { + case 'red': + return $this->getLayer(1); + break; + + case 'green': + return $this->getLayer(2); + break; + + case 'blue': + return $this->getLayer(3); + break; + + case 'alpha': + return $this->getLayer(4); + break; + + } + } + + /** + * merge channels. + * + * @param group of channels + * + * @return sets layer image to merge channels. + * + * @author email goodlittledeveloper@gmail.com + * + */ + + public function mergeChannels($group){ + $ChlR = $group->getLayer(1)->getResult(); + $ChlG = $group->getLayer(2)->getResult(); + $ChlB = $group->getLayer(3)->getResult(); + $ChlA = $group->getLayer(4)->getResult(); + + $imgtemp = imageCreateTrueColor($this->width,$this->height); + + imagealphablending($imgtemp, false); + imagesavealpha($imgtemp, true); + + for ($h=0; $h<$this->height; $h++){ + for ($w=0; $w<$this->width; $w++){ + + $Color["red"] = (imagecolorat($ChlR, $w, $h) >> 16) & 0xFF; + $Color["green"] = (imagecolorat($ChlG, $w, $h) >> 8) & 0xFF; + $Color["blue"] = imagecolorat($ChlB, $w, $h) & 0xFF; + $Color["alpha"] = (imagecolorat($ChlA, $w, $h) & 0x7F000000) >> 24; + + imagesetpixel($imgtemp,$w,$h,imagecolorallocatealpha($imgtemp,$Color["red"],$Color["green"],$Color["blue"],$Color["alpha"])); + } + } + + unset($ChlR); + unset($ChlG); + unset($ChlB); + unset($ChlA); + + unset($this->image); + $this->image = $imgtemp; + unset($imgtemp); + } + + + + /** * Apply horizontal or vertical flip (Transformation) * diff --git a/src/PHPImageWorkshop/Core/ImageWorkshopLib.php b/src/PHPImageWorkshop/Core/ImageWorkshopLib.php index 7f619cc..1f41af7 100644 --- a/src/PHPImageWorkshop/Core/ImageWorkshopLib.php +++ b/src/PHPImageWorkshop/Core/ImageWorkshopLib.php @@ -5,7 +5,13 @@ use PHPImageWorkshop\Core\Exception\ImageWorkshopLibException as ImageWorkshopLibException; // If no autoloader, uncomment these lines: -//require_once(__DIR__.'/Exception/ImageWorkshopLibException.php'); + + +if (!class_exists('ImageWorkshopLibException')) { + require_once(__DIR__.'/Exception/ImageWorkshopLibException.php'); +} + + /** * ImageWorkshopLib class diff --git a/src/PHPImageWorkshop/Exception/ImageWorkshopException.php b/src/PHPImageWorkshop/Exception/ImageWorkshopException.php index d7347d9..47458f0 100644 --- a/src/PHPImageWorkshop/Exception/ImageWorkshopException.php +++ b/src/PHPImageWorkshop/Exception/ImageWorkshopException.php @@ -5,7 +5,11 @@ use PHPImageWorkshop\Exception\ImageWorkshopBaseException as ImageWorkshopBaseException; // If no autoloader, uncomment these lines: -//require_once(__DIR__.'/ImageWorkshopBaseException.php'); + +if (!class_exists('ImageWorkshopBaseException')) { + require_once(__DIR__.'/ImageWorkshopBaseException.php'); +} + /** * ImageWorkshopException diff --git a/src/PHPImageWorkshop/ImageWorkshop.php b/src/PHPImageWorkshop/ImageWorkshop.php index d13e4c4..fe948c1 100644 --- a/src/PHPImageWorkshop/ImageWorkshop.php +++ b/src/PHPImageWorkshop/ImageWorkshop.php @@ -7,8 +7,13 @@ use PHPImageWorkshop\Exception\ImageWorkshopException as ImageWorkshopException; // If no autoloader, uncomment these lines: -//require_once(__DIR__.'/Core/ImageWorkshopLayer.php'); -//require_once(__DIR__.'/Exception/ImageWorkshopException.php'); + +if (!class_exists('ImageWorkshopLayer')) { // auto loads if not already loaded. + require_once(__DIR__.'/Core/ImageWorkshopLayer.php'); +} +if (!class_exists('ImageWorkshopException')) { + require_once(__DIR__.'/Exception/ImageWorkshopException.php'); +} /** * ImageWorkshop class @@ -135,6 +140,41 @@ public static function initVirginLayer($width = 100, $height = 100, $backgroundC return new ImageWorkshopLayer(ImageWorkshopLib::generateImage($width, $height, $backgroundColor, $opacity)); } + + /** + * Initialize a layer from a given image url + * + * + * @param string $url + * + * @return ImageWorkshopLayer + */ + + public static function initFromUrl($url) { + + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + + + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + + curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); + + $data = curl_exec($ch); + + curl_close($ch); + + + return $image = self::initFromString($data); + + } /** * Initialize a layer from a resource image var