Blending colors GD - PHP - php

Ok, I have a 64x64 pixels image, some pixels are white, some are grey, and some darker, so I have another 64x64 pixel image with some yellow pixels which will determine which pixels of the first image must be changed.
So far I could change the colors on the first image with the following code, but the thing is I have no idea how to "blend" the given color with the colors that were already on the first image.
For example, if a pixel is white (255,255,255) and the new color is red (255,0,0) the result will be (255,0,0) but if the pixel is a bit darker, the new red should also be darker. Any ideas?
$image = 'o1.png';
$overlay = 'o2.png';
$background = imagecreatefrompng($image);
imagealphablending($background, true);
// Create overlay image
$overlay = imagecreatefrompng($overlay);
// get size
$size = getimagesize("o2.png");
$L=$size[0];
$H=$size[1];
for($j=0;$j<$H;$j++){
for($i=0;$i<$L;$i++){
$rgb = imagecolorat($overlay, $i, $j);
$red = (isset($_GET['r']) ? $_GET['r'] : 0);
$green = (isset($_GET['g']) ? $_GET['g'] : 0);
$blue = (isset($_GET['b']) ? $_GET['b'] : 0);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
if(($r==255)&&($g==255)&&($b==0)) {
$color = imagecolorallocate($background, $red, $green, $blue);
imagesetpixel($background, $i, $j, $color);
}
}
}
header("Content-type: image/png");
header("Content-Disposition: filename=" . $image);
imagepng($background);
// Destroy the images
imagedestroy($background);
imagedestroy($overlay);

I think you are talking about multiply blend mode. The formula for this according to Wikipedia is:
Result Color = (Top Color) * (Bottom Color) /255
Using this formula the resulting image will be darker where the background color is darker.

Related

Retrieving and setting pixels individually

I'm trying to re-create a script I made in JavaScript; it bends an image by changing each pixels positions. I'm currently trying to port this to PHP, except when retrieving pixels and setting them, it doesn't appear correctly (I currently dont change the pixel locations). Below is my attempt:
<?php
header ('Content-Type: image/png');
$url = "https://www.google.co.uk/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
list($width, $height, $type, $attr) = getimagesize($url);
$original = imagecreatefrompng($url); //Google's logo
$image = imagecreate($width, $height); // our new image
//loop through all pixels..
for ($x = 0;$x<$width;$x++){
for ($y = 0;$y<$height;$y++){
$rgb = imagecolorat($original, $x,$y); //get colour data from $x $y coordinates
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
imagesetpixel($image,$x,$y,imagecolorallocate($image,$r,$g,$b));
//set pixel data on our new image at the same location with the same data
}
}
//retain a PNG's transparency
imagecolortransparent($image, imagecolorallocatealpha($image, 0, 0, 0, 127));
imagealphablending($image, false);
imagesavealpha($image, true);
imagepng($image);
imagedestroy($image);
imagedestroy($original);
?>
Here you can see (for testing purposes) I am using Google's logo, and im attempting to re-draw it pixel by pixel.. Below is the result. For some reason it only generates a very small portion of the image.. Any ideas?
Edit:
Here's the solution. As there isn't support for transparency using imagecreatetruecolor() I instead fill the image first with a white rectangle (if there is a solution for transparency, please create an answer).
<?php
header ('Content-Type: image/png');
$url = "https://www.google.co.uk/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
list($width, $height, $type, $attr) = getimagesize($url);
$source = imagecreatefrompng($url);
$image = imagecreatetruecolor($width, $height);
imagefilledrectangle($image, 0, 0, $width-1, $height-1, imagecolorallocatealpha($image, 255,255,255,0));
//fill with white rectangle to look transparent, but note that it isn't. Changing alpha channel merely shows
//a black background.
for ($x = 0;$x<$width;$x++){
for ($y = 0;$y<$height;$y++){
$rgb = imagecolorat($source, $x,$y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$colors = imagecolorsforindex($image, $rgb);
imagesetpixel($image,$x,$y,imagecolorallocatealpha($image,$colors["red"],$colors["green"],$colors["blue"],$colors["alpha"]));
//getting alpha from pixels for a real 'copy'
}
}
imagepng($image);
imagedestroy($image);
imagedestroy($source);
?>

Half Grayscale by imagefilter()

I know PHP's GD library can apply grayscale filter to an image, for example:
$img = imagecreatefrompng('test.png');
$img = imagefilter($img, IMG_FILTER_GRAYSCALE);
imagepng($img, 'test_updated.png');
Is there any method that can apply half of the grayscale effects (which is similar to CSS3's filter: grayscale(50%);) ?
I read from this answer, the grayscale filter is actually a reduction of R, G & B channel. Can I customize my own grayscale filter in PHP?
Reference: imagefilter()
Is there any method that can apply half of the grayscale effects
(which is similar to CSS3's filter: grayscale(50%);) ?
Found a script something similar what you are looking for..
<?php
function convertImageToGrayscale($source_file, $percentage)
{
$outputImage = ImageCreateFromJpeg($source_file);
$imgWidth = imagesx($outputImage);
$imgHeight = imagesy($outputImage);
$grayWidth = round($percentage * $imgWidth);
$grayStartX = $imgWidth-$grayWidth;
for ($xPos=$grayStartX; $xPos<$imgWidth; $xPos++)
{
for ($yPos=0; $yPos<$imgHeight; $yPos++)
{
// Get the rgb value for current pixel
$rgb = ImageColorAt($outputImage, $xPos, $yPos);
// extract each value for r, g, b
$rr = ($rgb >> 16) & 0xFF;
$gg = ($rgb >> 8) & 0xFF;
$bb = $rgb & 0xFF;
// Get the gray Value from the RGB value
$g = round(($rr + $gg + $bb) / 3);
// Set the grayscale color identifier
$val = imagecolorallocate($outputImage, $g, $g, $g);
// Set the gray value for the pixel
imagesetpixel ($outputImage, $xPos, $yPos, $val);
}
}
return $outputImage;
}
$image = convertImageToGrayscale("otter.jpg", .25);
header('Content-type: image/jpeg');
imagejpeg($image);
?>
See if that works. I found that here

Php IMG_FILTER_GRAYSCALE converting transparent pixels to black

I am trying to get my PNGs converted into grayscale and it almost works properly with this code:
$image = imagecreatefromstring(file_get_contents($this->image_dest."".$this->file_name));
imagefilter($image, IMG_FILTER_GRAYSCALE);
imagepng($image, $this->image_dest."".$this->file_name);
The problem is, when the image has some transparency, the transparent pixels are being rendered as black. I see there are others who have had the same question in part of their question, but it was never answered about this issue specifically.
I hope someone can help out with this!
If it helps, I was previously using this snippet to convert to greyscale, but it has the same problem with the transparent pixels in pngs being converted to black and I am not sure
how to detect the transparency and convert it using the imagecolorat function.
//Creates the 256 color palette
for ($c=0;$c<256;$c++){
$palette[$c] = imagecolorallocate($new,$c,$c,$c);
}
//Creates yiq function
function yiq($r,$g,$b){
return (($r*0.299)+($g*0.587)+($b*0.114));
}
//Reads the origonal colors pixel by pixel
for ($y=0;$y<$h;$y++) {
for ($x=0;$x<$w;$x++) {
$rgb = imagecolorat($new,$x,$y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
//This is where we actually use yiq to modify our rbg values, and then convert them to our grayscale palette
$gs = yiq($r,$g,$b);
imagesetpixel($new,$x,$y,$palette[$gs]);
}
}
Okay, this was mostly borrowed.. Don't quite remember where, but it should work:
//$im is your image with the transparent background
$width = imagesx($im);
$height = imagesy($im);
//Make your white background to overlay the original image on ($im)
$bg = imagecreatetruecolor($width, $height);
$white = imagecolorallocate($bg, 255, 255, 255);
//Fill it with white
imagefill($bg, 0, 0, $white);
//Merge the two together
imagecopyresampled($bg, $im, 0, 0, 0, 0, $width, $height, $width, $height);
//Convert to gray-scale
imagefilter($bg, IMG_FILTER_GRAYSCALE);
Hope that helps!

How can I set the transparancy to image for particular background color in image - using PHP - GD

Suppose I have any image(say passport type images where the background will be same around the user).
What I want to do is make that background image as transparent using PHP GD. So please let me know how can I achieve this? The example image is shown here. I want yellow color to be transparent.
What you basically want to do is replace colors 'close' to your background color. By 'close' I mean colors that are similar to it:
// $src, $dst......
$src = imagecreatefromjpeg("dmvpic.jpg");
// Alter this by experimentation
define( "MAX_DIFFERENCE", 20 );
// How 'far' two colors are from one another / color similarity.
// Since we aren't doing any real calculations with this except comparison,
// you can get better speeds by removing the sqrt and just using the squared portion.
// There may even be a php gd function that compares colors already. Anyone?
function dist($r,$g,$b) {
global $rt, $gt, $bt;
return sqrt( ($r-$rt)*($r-$rt) + ($g-$gt)*($g-$gt) + ($b-$bt)*($b-$bt) );
}
// Alpha color (to be replaced) is defined dynamically as
// the color at the top left corner...
$src_color = imagecolorat( $src ,0,0 );
$rt = ($src_color >> 16) & 0xFF;
$gt = ($src_color >> 8) & 0xFF;
$bt = $src_color & 0xFF;
// Get source image dimensions and create an alpha enabled destination image
$width = imagesx($src);
$height = imagesy($src);
$dst = =imagecreatetruecolor( $width, $height );
imagealphablending($dst, true);
imagesavealpha($dst, true);
// Fill the destination with transparent pixels
$trans = imagecolorallocatealpha( $dst, 0,0,0, 127 ); // our transparent color
imagefill( $dst, 0, 0, $transparent );
// Here we examine every pixel in the source image; Only pixels that are
// too dissimilar from our 'alhpa' or transparent background color are copied
// over to the destination image.
for( $x=0; $x<$width; ++$x ) {
for( $y=0; $y<$height; ++$y ) {
$rgb = imagecolorat($src, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
if( dist($r,$g,$b) > MAX_DIFFERENCE ) {
// Plot the (existing) color, in the new image
$newcolor = imagecolorallocatealpha( $dst, $r,$g,$b, 0 );
imagesetpixel( $dst, $x, $y, $newcolor );
}
}
}
header('Content-Type: image/png');
imagepng($dst);
imagedestroy($dst);
imagedestroy($src);
Please note above code is untested, I just typed it in stackoverflow so I may have some retarded spelling errors, but it should at bare minimal point you in the right direction.

PHP/GD, how to copy a circle from one image to another?

Is there a reasonably straightforward way to copy a circular area from one image resource to another? Something like imagecopymerge except with circles or ovals etc?
If possible, I want to avoid having to use pre-created image files (any oval shape should be possible), and if there's transparency colours involved they should naturally leave the rest of the image alone.
Reason I'm asking, I have a few classes that allow to apply image operations inside a "selected area" of an image, which works by first deleting that area from a copy of the image, then overlaying the copy back on the original. But what if you want to select a rectangle, and then inside that deselect a circle, and have the operations only affect the area that's left?
You could try this:
Start with original image - $img
Copy that image to a png - $copy
Create a mask png image of the area you want in the circle/ellipse (a 'magicpink' image with a black shape on it, with black set to the colour of alpha transparency) - $mask
Copy $mask over the top of $copy maintaining the Alpha transparency
Change what you need to on $copy
Copy $copy back over $img maintaining the Alpha transparency
// 1. Start with the original image
$img = imagecreatefromjpeg("./original.jpg");
$img_magicpink = imagecolorallocatealpha($img, 255, 0, 255, 127);
//imagecolortransparent($img, $img_magicpink);
// (Get its dimensions for copying)
list($w, $h) = getimagesize("./original.jpg");
// 2. Create the first copy
$copy = imagecreatefromjpeg("./original.jpg");
imagealphablending($copy, true);
$copy_magicpink = imagecolorallocate($copy, 255, 0, 255);
imagecolortransparent($copy, $copy_magicpink);
// 3. Create the mask
$mask = imagecreatetruecolor($w, $h);
imagealphablending($mask, true);
// 3-1. Set the masking colours
$mask_black = imagecolorallocate($mask, 0, 0, 0);
$mask_magicpink = imagecolorallocate($mask, 255, 0, 255);
imagecolortransparent($mask, $mask_black);
imagefill($mask, 0, 0, $mask_magicpink);
// 3-2. Draw the circle for the mask
$circle_x = $w/2;
$circle_y = $h/2;
$circle_w = 150;
$circle_h = 150;
imagefilledellipse($mask, $circle_x, $circle_y, $circle_w, $circle_h, $mask_black);
// 4. Copy the mask over the top of the copied image, and apply the mask as an alpha layer
imagecopymerge($copy, $mask, 0, 0, 0, 0, $w, $h, 100);
// 5. Do what you need to do to the image area
// My example is turning the original image gray and leaving the masked area as colour
$x = imagesx($img);
$y = imagesy($img);
$gray = imagecreatetruecolor($x, $y);
imagecolorallocate($gray, 0, 0, 0);
for ($i = 0; $i > 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
//for gray mode $r = $g = $b
$color = max(array($r, $g, $b));
$gray_color = imagecolorexact($img, $color, $color, $color);
imagesetpixel($gray, $i, $j, $gray_color);
}
}
// 6. Merge the copy with the origianl - maintaining alpha
imagecopymergegray($gray, $copy, 0, 0, 0, 0, $w, $h, 100);
imagealphablending($gray, true);
imagecolortransparent($gray, $mask_magicpink);
header('Content-Type: image/png');
imagepng($gray);
imagedestroy($gray);

Categories