How can one specify an image and apply a radial transparent gradient where it fades out radially. I do not have Imagemagick installed.
Marginal example:
How can one specify an image and apply a radial transparent gradient where it fades out radially. I do not have Imagemagick installed.
Marginal example:
Introduction
I think you should get Imagemagick installed because what you want is a simple vignette
effect, You can easily so that with ImageMagic (convert input.jpg -background black -vignette 70x80 output.png
) without having to loop every pixel which can be very slow when dealing with large images
Original Image
$file = __DIR__ . "/golf.jpg";
Effect 1
$image = new imagick($file);
$image->vignetteImage(20, 20, 40, - 20);
header("Content-Type: image/png");
echo $image;
Effect 2
$image = new imagick($file);
$image->vignetteImage(100, 100, 200, 200);
header("Content-Type: image/png");
echo $image;
vignette with GD
Well if you are forced to use GB ... Use can use this cool vignette script
function vignette($im) {
$width = imagesx($im);
$height = imagesy($im);
$effect = function ($x, $y, &$rgb) use($width, $height) {
$sharp = 0.4; // 0 - 10 small is sharpnes,
$level = 0.7; // 0 - 1 small is brighter
$l = sin(M_PI / $width * $x) * sin(M_PI / $height * $y);
$l = pow($l, $sharp);
$l = 1 - $level * (1 - $l);
$rgb['red'] *= $l;
$rgb['green'] *= $l;
$rgb['blue'] *= $l;
};
for($x = 0; $x < imagesx($im); ++ $x) {
for($y = 0; $y < imagesy($im); ++ $y) {
$index = imagecolorat($im, $x, $y);
$rgb = imagecolorsforindex($im, $index);
$effect($x, $y, $rgb);
$color = imagecolorallocate($im, $rgb['red'], $rgb['green'], $rgb['blue']);
imagesetpixel($im, $x, $y, $color);
}
}
return (true);
}
Faster GD vignette approach
A better approached used in GD Filter testing would be ... to create a mask and over lay
$overlay = 'vignette_white.png';
$png = imagecreatefrompng($overlay);
imagecopyresampled($filter, $png, 0, 0, 0, 0, $width, $height, $width, $height);
The only disadvantage is that The image must be the same size with the mask for the effect to look cool
Conclusion
If this is what you mean by radial transparent gradient
then i advice you to get ImageMagic
if not at least the lady the picture is cute.
Thanks to the function linked by @Baba I was able to alter the script to allow for semi transparent vignette effect.
<?php
class PhotoEffect
{
private $_photoLocation;
private $_width;
private $_height;
private $_type;
private $_originalImage;
private $_afterImage;
/**
* Load image URL in constructor
*/
final public function __construct($photoLocation)
{
$this->_photoLocation = $photoLocation;
if (!$size = @getimagesize($this->_photoLocation)){
throw new Exception('Image cannot be handled');
}
$this->_width = $size[0];
$this->_height = $size[1];
$this->_type = $size[2];
switch ( $this->_type ) {
case IMAGETYPE_GIF:
$this->_originalImage = imagecreatefromgif($this->_photoLocation);
break;
case IMAGETYPE_JPEG:
$this->_originalImage = imagecreatefromjpeg($this->_photoLocation);
break;
case IMAGETYPE_PNG:
$this->_originalImage = imagecreatefrompng($this->_photoLocation);
break;
default:
throw new Exception('Unknown image type');
}
}
/**
* Destroy created images
*/
final private function __destruct() {
if (!empty($this->_originalImage))
{
imagedestroy($this->_originalImage);
}
if (!empty($this->_afterImage))
{
imagedestroy($this->_afterImage);
}
}
/**
* Apply vignette effect
*/
final public function Vignette($sharp=0.4, $level=1, $alpha=1)
{
if (empty($this->_originalImage))
{
throw new Exception('No image');
}
if (!is_numeric($sharp) || !($sharp>=0 && $sharp<=10))
{
throw new Exception('sharp must be between 0 and 10');
}
if (!is_numeric($level) || !($level>=0 && $level<=1))
{
throw new Exception('level must be between 0 and 10');
}
if (!is_numeric($alpha) || !($alpha>=0 && $alpha<=10))
{
throw new Exception('alpha must be between 0 and 1');
}
$this->_afterImage = imagecreatetruecolor($this->_width, $this->_height);
imagesavealpha($this->_afterImage, true);
$trans_colour = imagecolorallocatealpha($this->_afterImage, 0, 0, 0, 127);
imagefill($this->_afterImage, 0, 0, $trans_colour);
for($x = 0; $x < $this->_width; ++$x){
for($y = 0; $y < $this->_height; ++$y){
$index = imagecolorat($this->_originalImage, $x, $y);
$rgb = imagecolorsforindex($this->_originalImage, $index);
$l = sin(M_PI / $this->_width * $x) * sin(M_PI / $this->_height * $y);
$l = pow($l, $sharp);
$l = 1 - $level * (1 - $l);
$rgb['red'] *= $l;
$rgb['green'] *= $l;
$rgb['blue'] *= $l;
$rgb['alpha'] = 127 - (127 * ($l*$alpha));
$color = imagecolorallocatealpha($this->_afterImage, $rgb['red'], $rgb['green'], $rgb['blue'], $rgb['alpha']);
imagesetpixel($this->_afterImage, $x, $y, $color);
}
}
}
/**
* Ouput PNG with correct header
*/
final public function OutputPng()
{
if (empty($this->_afterImage))
{
if (empty($this->_originalImage))
{
throw new Exception('No image');
}
$this->_afterImage = $this->_originalImage;
}
header('Content-type: image/png');
imagepng($this->_afterImage);
}
/**
* Save PNG
*/
final public function SavePng($filename)
{
if (empty($filename)) {
throw new Exception('Filename is required');
}
if (empty($this->_afterImage))
{
if (empty($this->_originalImage))
{
throw new Exception('No image');
}
$this->_afterImage = $this->_originalImage;
}
imagepng($this->_afterImage, $filename);
}
}
/**
* How to use
*/
$effect = new PhotoEffect('test.jpg');
$effect->Vignette();
$effect->OutputPng();
?>
Working phpfiddle with the only image I could find on their server, so not that big.
I am aware that this is a PHP related question, but you can achieve nice transparent gradients with use of javascript and html5 canvas element.
So I wrote this small script that:
grd.addColorStop()
) to change the flow of the gradientscript
window.onload = function() {
if ( typeof CanvasRenderingContext2D !== 'function' ) {
document.getElementById('gradient-image').style.visibility = "visible";
return;
}
var image = document.getElementById('gradient-image');
// these are the default values, change them for custom shapes
create_gradient( image, image.width/2, image.height/2, image.height/4, image.width/2, image.height/2, image.height/2 );
}
function create_gradient( image, start_x, start_y, start_r, end_x, end_y, end_r ){
var canvas = document.createElement('canvas');
var parent = image.parentNode;
if ( parent.lastchild == image ) parent.appendChild(canvas);
else parent.insertBefore(canvas, image.nextSibling);
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
var grd = context.createRadialGradient( start_x, start_y, start_r, end_x, end_y, end_r );
grd.addColorStop(0, 'rgba(0,0,0,1)' );
// grd.addColorStop(0.2, 'rgba(0,0,0,0.8)' );
grd.addColorStop(1, 'rgba(0,0,0,0)' );
context.fillStyle = grd;
context.fillRect(0, 0, image.width, image.height);
var grd_data = context.getImageData(0, 0, image.width, image.height);
context.drawImage( image, 0, 0);
var img_data = context.getImageData(0, 0, image.width, image.height);
var grd_pixel = grd_data.data;
var img_pixel = img_data.data;
var length = img_data.data.length
for ( i = 3; i < length; i += 4 ) {
img_pixel[i] = grd_pixel[i];
}
context.putImageData(img_data, 0, 0);
}
html
<img id="gradient-image"src="">
css
#gradient-image {
position: absolute;
visibility: hidden;
}
There is also a vignette filter available in this php library, which only uses GD: