PHP using imageline and XOR - php

I am trying to use the image GD library to draw lines using an XOR filter. I have not been able to find an easy way to do this so a line being drawn "flips" white to black and vice-versus. Any solutions?

I'm pretty sure that it's not possible to draw the XOR line with built-in imageline PHP function. Though you can draw it yourself with imagesetpixel and custom line drawing algorithm. For example something like this can work (Bresenham Line Algorythm for PHP):
function line($im,$x1,$y1,$x2,$y2) {
$deltax=abs($x2-$x1);
$deltay=abs($y2-$y1);
if ($deltax>$deltay) {
$numpixels=$deltax+1;
$d=(2*$deltay)-$deltax;
$dinc1=$deltay << 1; $dinc2=($deltay-$deltax) << 1;
$xinc1=1; $xinc2=1;
$yinc1=0; $yinc2=1;
} else {
$numpixels=$deltay+1;
$d=(2*$deltax)-$deltay;
$dinc1=$deltax << 1; $dinc2=($deltax-$deltay)<<1;
$xinc1=0; $xinc2=1;
$yinc1=1; $yinc2=1;
}
if ($x1>$x2) {
$xinc1=-$xinc1;
$xinc2=-$xinc2;
}
if ($y1>$y2) {
$yinc1=-$yinc1;
$yinc2=-$yinc2;
}
$x=$x1;
$y=$y1;
for ($i=0;$i<$numpixels;$i++) {
$color_current = imagecolorat ( $im, $x, $y );
$r = ($color_current >> 16) & 0xFF;
$g = ($color_current >> 8) & 0xFF;
$b = $color_current & 0xFF;
$color = imagecolorallocate($im, 255 - $r, 255 - $g, 255 - $b);
imagesetpixel($im,$x,$y,$color);
if ($d<0) {
$d+=$dinc1;
$x+=$xinc1;
$y+=$yinc1;
} else {
$d+=$dinc2;
$x+=$xinc2;
$y+=$yinc2;
}
}
return ;
}
Function perfectly works for images, created from files.

Related

Change “Saturation” of an image with PHP GD Library?

There is an excellent answer on how to change the HUE of an image using PHP-GD library. But I need to know how to change the SATURATION of an image using PHP-GD. Here is a copy of the code from the answer which successfully changes the HUE of the image.
function imagehue(&$image, $angle) {
if($angle % 360 == 0) return;
$width = imagesx($image);
$height = imagesy($image);
for($x = 0; $x < $width; $x++) {
for($y = 0; $y < $height; $y++) {
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$alpha = ($rgb & 0x7F000000) >> 24;
list($h, $s, $l) = rgb2hsl($r, $g, $b);
$h += $angle / 360;
if($h > 1) $h--;
list($r, $g, $b) = hsl2rgb($h, $s, $l);
imagesetpixel($image, $x, $y, imagecolorallocatealpha($image, $r, $g, $b, $alpha));
}
}
}
If you need to take a look at the code of helper functions rgb2hsl and hsl2rgb please check the original answer. Since Hue is one of the parameters of HSL, I thought I could modify the function somehow to get a working solution for Saturation. Despite of limited php skills I had to try but it did not work and produced bizarre results. Here is the modification that I am trying.
MODIFIED CODE: UPDATED as suggested by #mark
function imageSaturation(&$image, $saturationPercentage) {
$width = imagesx($image);
$height = imagesy($image);
for($x = 0; $x < $width; $x++) {
for($y = 0; $y < $height; $y++) {
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$alpha = ($rgb & 0x7F000000) >> 24;
list($h, $s, $l) = rgb2hsl($r, $g, $b);
$s = $s * (100 + $saturationPercentage ) /100;
if($s > 1) $s = 1;
list($r, $g, $b) = hsl2rgb($h, $s, $l);
imagesetpixel($image, $x, $y, imagecolorallocatealpha($image, $r, $g, $b, $alpha));
}
}
}
header('Content-type: image/png');
$image = imagecreatefrompng('rgb.png');
imageSaturation($image, -80);//bring down current image saturation to 80%
imagepng($image);
EFFORTS UPDATE :
It has been pointed out to me by #Dai that these lines help construct a color code of an individual RGB pixel. So I guess this part can remained unchanged ?
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$alpha = ($rgb & 0x7F000000) >> 24;
In the next line we are simply converting the RGB values to HSL with rgb2hsl($r, $g, $b); and assigning it to list($h, $s, $l). The point I am stuck at the moment are these lines.
$s += $saturationPercentage / 100;
if($s > 1) $s--;
I understand the syntax, but not sure how I handle these or if they are even required. If not an answer helpful hints / suggestions would be great. I am trying the code on this image to bring down the saturation from 100% to 80%, but I am getting this image as result.
I think you need something like
$s=$s * (100+$saturationPercentage)/100
else you are just adding a constant to each value rather than a percentage of the existing value.
Also, where you decrement 1 if your new saturation exceeds 1, you probaly would be better just setting it to 1.0, i.e. fully saturated like this:
if($s>1)$s=1
otherwise, say the resulting saturation is 1.3 (i.e. very, very saturated) you will make that into 0.3, i.e. very undersaturated, instead of 1.0 (fully saturated).
So, if $s is 0.7, and you add 10%, you will get
$s = 0.7 * (100 + 10)/100
$s = 0.7 * 1.1
$s = 0.77

Calculate colordifference

Is it possible to check if a certain hexadecimal color is closer to FFF or 000 based on a defined 'center-value'?
I want to check if a color lies closer to #FFF or #000 based on #888.
So if I check for #EFEFEF it should return #FFF and if I try #878787 it should return #000.
How can this be achieved? I'm not sure what to search for on Google...
Thanks in advance
You could convert the colours to numbers:
$color_num = hexdec(substr($color, 1)); // skip the initial #
Then compare them to either 0x0 or 0xffffff.
You could also break them down into R, G and B and make three comparisons; then average them? Not sure how precise you want this thing :)
The easiest way to solve your problem is to calculate the distance between colors using their greyscale values (there are other ways, but this is simple). So something like:
// returns a distance between two colors by comparing each component
// using average of the RGB components, eg. a grayscale value
function color_distance($a, $b)
{
$decA = hexdec(substr($a, 1));
$decB = hexdec(substr($a, 1));
$avgA = (($decA & 0xFF) + (($decA >> 8) & 0xFF) + (($decA >> 16) & 0xFF)) / 3;
$avgB = (($decB & 0xFF) + (($decB >> 8) & 0xFF) + (($decB >> 16) & 0xFF)) / 3;
return abs($avgA - $avgB);
}
// I am going to leave the naming of the function to you ;)
// How this works is that it'll return $minColor if $color is closer to $refColorMin
// and $maxColor if $color is closer to $refColorMax
// all colors should be passed in format #RRGGBB
function foo($color, $refColorMin, $refColorMax, $minColor, $maxColor)
{
$distMin = color_distance($color, $refColorMin);
$distMax = color_distance($color, $refColorMax);
return ($distMin < $distMax) ? $minColor : $maxColor;
}
// Example usage to answer your original question:
$colorA = foo('#EFEFEF', '#888888', '#FFFFFF', '#000000', '#FFFFFF');
$colorA = foo('#898989', '#888888', '#FFFFFF', '#000000', '#FFFFFF');
// Check the values
var_dump($colorA, $colorB);
The output is:
string(7) "#FFFFFF"
string(7) "#000000"
You could do something like the following:
function hex2rgb($hex) {
$hex = str_replace("#", "", $hex);
if(strlen($hex) == 3) {
$r = hexdec(substr($hex,0,1).substr($hex,0,1));
$g = hexdec(substr($hex,1,1).substr($hex,1,1));
$b = hexdec(substr($hex,2,1).substr($hex,2,1));
} else {
$r = hexdec(substr($hex,0,2));
$g = hexdec(substr($hex,2,2));
$b = hexdec(substr($hex,4,2));
}
$rgb = array($r, $g, $b);
//return implode(",", $rgb); // returns the rgb values separated by commas
return $rgb; // returns an array with the rgb values
}
$rgb = hex2rgb("#cc0");
From that you could take the values of $rgb and see if their values, on average, area greater than or less than 122.5. If its greater than 122.5 you'd be closer to #FFFFFF, lower than 122.5 you'd be closer to #000000.
Thanks everybody for the help!
In my startpost I made a little typo as mentioned by oezi. For me the solution was a small modification to the accepted answer (by reko_t):
function color_distance($sColor1, $sColor2)
{
$decA = hexdec(substr($sColor1, 1));
$decB = hexdec(substr($sColor2, 1));
$avgA = (($decA & 0xFF) + (($decA >> 8) & 0xFF) + (($decA >> 16) & 0xFF)) / 3;
$avgB = (($decB & 0xFF) + (($decB >> 8) & 0xFF) + (($decB >> 16) & 0xFF)) / 3;
return abs($avgA - $avgB);
}
function determine_color($sInputColor, $sRefColor, $sMinColor, $sMaxColor)
{
$distRef = color_distance($sInputColor, $sRefColor);
$distMin = color_distance($sInputColor, $sMinColor);
$distMax = color_distance($sInputColor, $sMaxColor);
return $distMax - $distRef < $distMin - $distRef ? $sMinColor : $sMaxColor;
}
I needed this function to determine text-color on a background-color which can be set by some setting. Thanks! :) Credits to reko_t!

Check pixels pattern

How can I check for a pixel pattern in PHP?
I mean I wanna use as condition that pixel A has xxx value and the following pixel B has another value yyy.
This is what I wrote:
$img = imagecreatefrompng("myimage.png");
$w = imagesx($img);
$h = imagesy($img);
for($y=0;$y<$h;$y++) {
for($x=0;$x<$w;$x++) {
$rgb = imagecolorat($img, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
echo "#".$r.$g.$b.",";
$pixel = $r.$g.$b;
if ($pixel == "481023" and $pixel+1???
}
echo "<br />\r\n";
}
I'd like to ask also if I can speed up the whole thing by incrementing the $x value by 2 every for cycle. This because I have a pattern of 2 pixels, maybe I can use something like:
for($x=0;$x<$w;$x+2) {
//...
if ($pixel == "xxx") {//check the following pixel}
else if ($pixel == "yyy") {//check the previous pixel}
}
You might want to define a function like:
function getpixelat($img,$x,$y) {
$rgb = imagecolorat($img,$x,$y);
$r = dechex(($rgb >> 16) & 0xFF);
$g = dechex(($rgb >> 8) & 0xFF);
$b = dechex($rgb & 0xFF);
return $r.$g.$b;
}
Notice the dechex - you need this if you want it to look like an HTML colour code. Otherwise "white" would be 255255255 instead of ffffff and you'd also get ambiguous colours - is 202020 a dark gray (20,20,20) or "red with a slight hint of blue" (202,0,20)?
Once you have this, it should be a simple matter:
for( $y=0; $y<$h; $y++) {
for( $x=0; $x<$w; $x++) {
$pixel = getpixelat($img,$x,$y);
if( $pixel == "481023" && getpixelat($img,$x+1,$y) == "998877") {
// pattern! Do something here.
$x++; // increment X so we don't bother checking the next pixel again.
}
}
}

How to replace pixels in an image in PHP?

I'd like to loop through each row and column in an image and replace certain pixels with different colors. I am open to a solution using GD or ImageMagick. Can anyone give me an example of how to do this? I've Googled several different ways and haven't found a solid example.
You can achieve this with GD by something like:
You will be handling colors as hex values
function replaceColor($img, $from, $to) {
$r = hexdec(substr($to, 0, 2));
$g = hexdec(substr($to, 2, 2));
$b = hexdec(substr($to, 4, 2));
// allocate $to color.
$to = imagecolorallocate($img, $r, $g, $b);
// pixel by pixel grid.
for ($y = 0; $y < imagesy($img); $y++) {
for ($x = 0; $x < imagesx($img); $x++) {
// find hex at x,y
$at = imagecolorat($img, $x, $y);
$r = 0xFF & ($at >> 0x10);
$g = 0xFF & ($at >> 0x8);
$b = 0xFF & ($at);
$hex = dechex($r).dechex($g).dechex($b);
// set $from to $to if hex matches.
if ($hex == $from) {
imagesetpixel($img, $x, $y, $to);
}
}
}
}

Pixel per Pixel image, transparent turned into black

I read a couple of thing about this, but I can't figure how to put it in my code.
Here it is :
function go($image) {
// Open the image
$getimage=imagecreatefrompng($image);
//Get the width/height
$w = imagesx($getimage);
$h = imagesy($getimage);
//init Count variable, when it reach the width, skip a line
$count = 0;
// For each line
for($y=0;$y<$h;$y++) {
// For each column
for($x=0;$x<$w;$x++) {
$rgba = imagecolorat($getimage, $x, $y);
$r = ($rgba >> 16) & 0xFF;
$g = ($rgba >> 8) & 0xFF;
$b = $rgba & 0xFF;
$a = ($rgba & 0x7F000000) >> 24;
echo '<div class="pix" style="background-color: rgba('.$r.', '.$g.', '.$b.', '.$a.');"></div>';
$count++;
if($count==$w) {echo '<br>'; $count = 0; }
}
}
echo $pixel_gen;
}
If oyu want to see what it looks like, clic here: http://narks.xtreemhost.com/
And double-click on any icon, popup will appear. (Note: dbl-clinking on any icon will show the same image (I didnt fixed this yet)
Any idea how i can make the black pixel appear like the real pixel with alpha) ?
Thanks for your help!
EDITED
(New code, i put only the first lines since i want to save space)
function go($image) {
// Open the image
$getimage=imagecreatefrompng($image);
imagealphablending($getimage, false);
imagesavealpha($getimage, true);
//Get the width/height
$w = imagesx($getimage);
$h = imagesy($getimage);
[...]
To see what it looks like now, visit the website above and double-click on an icon.
EDIT 2
I just tried (for a test) with :
$getimage=imagecreatefrompng('iconDB/lib/chat_fav_48.png');
imagealphablending($getimage, false);
imagesavealpha($getimage, true);
header("Content-type: image/png");
imagepng($getimage);
imagedestroy($getimage);
and then with
$getimage=imagecreatefrompng('iconDB/lib/chat_fav_48.png');
header("Content-type: image/png");
imagepng($getimage);
imagedestroy($getimage);
The first is okay and the second make pixels black. So it is when i get each pixel's RGB colors and when I display it. Anyone see a mistake there?
Here is the correct working code, in order to complete this question.
function go($image) {
// Open the image
$getimage=imagecreatefrompng($image);
imagealphablending($getimage, true);
imagesavealpha($getimage, true);
//Get the width/height
$w = imagesx($getimage);
$h = imagesy($getimage);
//init Count variable, when it reach the width, skip a line
$count = 0;
// For each line
for($y=0;$y<$h;$y++) {
// For each column
for($x=0;$x<$w;$x++) {
// Get the image color for this pixel
$rgba = imagecolorat($getimage, $x, $y);
$r = ($rgba >> 16) & 0xFF;
$g = ($rgba >> 8) & 0xFF;
$b = $rgba & 0xFF;
$a = ($rgba & 0x7F000000) >> 24;
//Calculating the correct Alpha value for rgba display in css
$a = (127-$a)/127;
echo '<div class="pix" style="background-color: rgba('.$r.', '.$g.', '.$b.', '.$a.');"></div>';
$count++;
if($count==$w) {echo '<br>'; $count = 0; }
}
}
echo $pixel_gen;
}
I hope it will be useful for someone
According to comments on the imagecreatefrompng page, you need to call imagealphablending and imagesavealpha
imagealphablending($getimage, false);
imagesavealpha($getimage, true);
There are also other comments about alpha transparency and PNGs on that page.

Categories