Pixel per Pixel image, transparent turned into black - php

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.

Related

How to create grid based on luma numbers

I have 555 photos in a directory. They get scanned and given a number from 1 through 100 based on the brightness of the photo.
My goal is to have these images in a 37x15 rectangular grid where the centermost horizontal row of images are the brightest and then the outward images are the darkest.
So the ending result would be the images being renamed img[1].jpg img[2].jpg img[3].jpg from the top left to the bottom right, once I combine these later, they would be a gradient of the bottom and top being the darkest images, and the center most horizontal images being the brightest in color.
I already have a function that determines the brightness between 0-100, and a loop for the rows that determine the values row, but stuck after that.
function getAvgLuminance($filename, $num_samples=30) {
global $rows;
// needs a mimetype check
$img = imagecreatefromjpeg($filename);
$width = imagesx($img);
$height = imagesy($img);
$x_step = intval($width/$num_samples);
$y_step = intval($height/$num_samples);
$total_lum = 0;
$sample_no = 1;
for ($x=0; $x<$width; $x+=$x_step) {
for ($y=0; $y<$height; $y+=$y_step) {
$rgb = imagecolorat($img, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// choose a simple luminance formula from here
// http://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color
$lum = ($r+$r+$b+$g+$g+$g)/6;
$total_lum += $lum;
$sample_no++;
}
}
// work out the average
$avg_lum = $total_lum / $sample_no;
return ($avg_lum / 255) * $rows;
}
$rows=36;
$col=14;
$imgs_resource_dir = 'imgs';
$allFiles = scandir($imgs_resource_dir);
$imlist=array_diff($allFiles, array('.', '..'));
$rowCenter = $rows/2;
while($rows > $ri++){
$FromTop = ( $rowCenter - $ri );
$FromBottom = $rowCenter- ( $rows-$ri) ;
$RowPoint = $FromTop > 0 ? $FromTop : $FromBottom;
}// end row loop
//start image loop
foreach($imlist as $imgfile ){
$pathtoImage = $imgs_resource_dir.'/'.$imgfile ;
$lumss= getAvgLuminance($pathtoImage);
echo 'str '.$lumss.'<br>';
}//end foreach loop

Php Image Transformation not Doing What I Expect It to Do

The following block of php code is supposed to take this image as input snd produce this image as output (convert the black to yellow and the light-blue to black):
However, I'm getting this image as output instead.
Can anyone see the problem with my code?
$im = imagecreatefrompng("./input.png");
$width = imagesx($im);
$height = imagesy($im);
$new = imagecreate($width, $height);
imagecopy($new, $im, 0, 0, 0, 0, $width, $height);
imagecolorset($new, imagecolorexact($new, 0, 0, 0), 255, 255, 0);
for($i = 0; $i < $width; $i++) {
for($j = 0; $j < $height; $j++) {
$index = imagecolorat($new, $i, $j);
$rgb = imagecolorsforindex($new, $index);
if($rgb['red'] != 255 && $rgb['green'] != 255 && $rgb['blue'] != 0) {
echo '(' . $i . ', ' . $j . ')' . 'color => (' . (255 - $rgb['blue']) . ', ' . (255 - $rgb['blue']) . ', 0)<br />';
$color = imagecolorallocate($new, 255 - $rgb['blue'], 255 - $rgb['blue'], 0);
imagesetpixel($new, $i, $j, $color);
}
unset($index);
unset($rgb);
}
}
imagepng($new, 'tesst.png');
imagedestroy($im);
imagedestroy($new);
I believe the source of the issue here is that when using a palette based image, such as the one you have created by calling imagecreate(), it is possible to declare the same color at multiple indexes within the palette.
This means that, because you are calling imagecolorallocate() on every iteration, the palette eventually becomes full and imagecolorallocate() starts returning false (this can be seen if you var_dump($color); before the imagesetpixel() call). false evaluates to zero when cast to an integer - so when the palette fills up, all remaining pixels are effectively converted to the background color.
There are two things that you could do about this, the first and probably easiest is just to use a true-color image, which is just a simple case of changing imagecreate($width, $height); to imagecreatetruecolor($width, $height);.
If you want to stick with the palette-based image (for example for reasons of output image data size - with an image containing so few colors, a palette-based image will be considerably smaller), you will need to cache the allocated colors manually so you can re-use them, something like this:
// ...
$colors = array();
for ($x = 0; $x < $width; $x++) { // iterate x axis
for ($y = 0; $y < $height; $y++) { // iterate y axis
// Get the color at this index
$index = imagecolorat($new, $x, $y);
// Only allocate a new color if not already done
if (!isset($colors[$index])) {
$rgb = imagecolorsforindex($new, $index);
if ($rgb['red'] != 255 || $rgb['green'] != 255 || $rgb['blue'] != 0) {
// If it's not the background color allocate a new color
$r = $g = 255 - $rgb['blue'];
$b = 0;
$colors[$index] = imagecolorallocate($new, $r, $g, $b);
} else {
// Otherwise set the index to false, we can ignore it
$colors[$index] = false;
}
}
// If there's something to do, do it
if ($colors[$index] !== false) {
imagesetpixel($new, $x, $y, $colors[$index]);
}
}
}
// ...
You may also wish to track the colors in use in the image so you can "cleanse the palette" afterwards (i.e. deallocate any colors that are no longer in use in the image, which will further help with the data size reduction). Although arguably it would be better, in this case, to start with a clean palette and inspect the old image resource to get the pixel details, instead of copying the original to a new image resource.
yes your
$color = imagecolorallocate($new, 255 - $rgb['blue'], 255 - $rgb['blue'], 0);
is messing everything up..
if you desire the same output... just paste the line outside for loop this will solve your problem if you want the specific image:
$color = imagecolorallocate($new, 35, 35, 0); //got from debugging
and it will get u the desired output.
Dins

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 find the Dominant color in image?

i want to find the dominant color in image,
how can i do it ?
it would be great if i can get this in HEX code (exm: #eeeeee)
To find the most "dominant" color in an image, meaning the color that is most prevalent in the image: you'd need to create a histogram of the image.
Here is an the code from this article on how to create a histogram in PHP. (Website has gone off line several times)
<?php
$source_file = "test_image.jpg";
// histogram options
$maxheight = 300;
$barwidth = 2;
$im = ImageCreateFromJpeg($source_file);
$imgw = imagesx($im);
$imgh = imagesy($im);
// n = total number or pixels
$n = $imgw*$imgh;
$histo = array();
for ($i=0; $i<$imgw; $i++)
{
for ($j=0; $j<$imgh; $j++)
{
// get the rgb value for current pixel
$rgb = ImageColorAt($im, $i, $j);
// extract each value for r, g, b
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// get the Value from the RGB value
$V = round(($r + $g + $b) / 3);
// add the point to the histogram
$histo[$V] += $V / $n;
}
}
// find the maximum in the histogram in order to display a normated graph
$max = 0;
for ($i=0; $i<255; $i++)
{
if ($histo[$i] > $max)
{
$max = $histo[$i];
}
}
echo "<div style='width: ".(256*$barwidth)."px; border: 1px solid'>";
for ($i=0; $i<255; $i++)
{
$val += $histo[$i];
$h = ( $histo[$i]/$max )*$maxheight;
echo "<img src=\"img.gif\" width=\"".$barwidth."\"
height=\"".$h."\" border=\"0\">";
}
echo "</div>";
?>
In that example $max is your most "dominant" color.
There is a PHP class developed that handles this, named color extract. However, know that doing this on the server side will require substantial system resources. You may wish to instead do this with canvas.
Try this: http://www.coolphptools.com/color_extract.
The Image Color Extract PHP class pulls the most common colors (in percentages) out of an image file. The color values are in hexadecimal.
Sounds like a delightful code to write! I made a function awhile back that goes through every pixel and adds a shade to each one. What you could do is:
For Each Pixel, find the highest color (r,g,or b) and do the math ($colorG++ or something)
at the end, find out what one is the largest, and there would be your highest rgb shade.
I wonder what color would come out if you used the resulting rgb value...
In regard to tkone answer, the $max is just a parameter showing density of the color at an image. I would change the code a bit to return the HEX color:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Empty Document</title>
</head>
<body>
<?php
error_reporting(0);
function rgb2hex($rgb) {
$hex = "#";
$hex .= str_pad(dechex($rgb[0]), 2, "0", STR_PAD_LEFT);
$hex .= str_pad(dechex($rgb[1]), 2, "0", STR_PAD_LEFT);
$hex .= str_pad(dechex($rgb[2]), 2, "0", STR_PAD_LEFT);
return $hex; // returns the hex value including the number sign (#)
}
$source_file = "image.jpg";
// histogram options
$maxheight = 300;
$barwidth = 2;
$im = ImageCreateFromJpeg($source_file);
$imgw = imagesx($im);
$imgh = imagesy($im);
// n = total number or pixels
$n = $imgw*$imgh;
$histo = array();
for ($i=0; $i<$imgw; $i++)
{
for ($j=0; $j<$imgh; $j++)
{
// get the rgb value for current pixel
$rgb = ImageColorAt($im, $i, $j);
//echo $rgb."<br>";
// extract each value for r, g, b
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// get the Value from the RGB value
$V = round(($r + $g + $b) / 3);
//echo $V."<br>";
// add the point to the histogram
$histo[$V] += $V / $n;
$histo_color[$V] = rgb2hex([$r,$g,$b]);
}
}
// find the maximum in the histogram in order to display a normated graph
$max = 0;
for ($i=0; $i<255; $i++)
{
if ($histo[$i] > $max)
{
$max = $histo[$i];
}
}
echo "<div style='width: ".(256*$barwidth)."px; border: 1px solid'>";
for ($i=0; $i<255; $i++)
{
$val += $histo[$i];
$h = ( $histo[$i]/$max )*$maxheight;
echo "<img src=\"img.gif\" width=\"".$barwidth."\"
height=\"".$h."\" border=\"0\">";
}
echo "</div>";
$key = array_search ($max, $histo);
$col = $histo_color[$key];
?>
<p style="min-width:100px; min-height:100px; background-color:<?php echo $col?>;"></p>
<img src="<?php echo $source_file?>">
</body>
</html>
Also, it is worth mentioning that this is just the most 'repeated' color at the image that cannot absolutely considered 'dominant' color.
PHP Simple Color Thief
🖼 Detect the Dominant Color used in an Image
Works very fast!
PHP:
require 'color.php';
$image = 'https://cdn.pixabay.com/photo/2012/11/24/07/43/colorful-67134_960_720.jpg'
$default_color = 'ffffff';
echo simple_color_thief($image, $default_color);
Will return the Hex Color: e0a654
The color.php File:
/*
PHP Simple Color Thief
======================
Detect the Dominant Color used in an Image
Copyright 2019 Igor Gaffling
*/
function simple_color_thief($img, $default='eee') {
if(#exif_imagetype($img)) { // CHECK IF IT IS AN IMAGE
$type = getimagesize($img)[2]; // GET TYPE
if ($type === 1) { // GIF
$image = imagecreatefromgif($img);
// IF IMAGE IS TRANSPARENT (alpha=127) RETURN fff FOR WHITE
if (imagecolorsforindex($image, imagecolorstotal($image)-1)['alpha'] == 127) return 'fff';
} else if ($type === 2) { // JPG
$image = imagecreatefromjpeg($img);
} else if ($type === 3) { // PNG
$image = imagecreatefrompng($img);
// IF IMAGE IS TRANSPARENT (alpha=127) RETURN fff FOR WHITE
if ((imagecolorat($image, 0, 0) >> 24) & 0x7F === 127) return 'fff';
} else { // NO CORRECT IMAGE TYPE (GIF, JPG or PNG)
return $default;
}
} else { // NOT AN IMAGE
return $default;
}
$newImg = imagecreatetruecolor(1, 1); // FIND DOMINANT COLOR
imagecopyresampled($newImg, $image, 0,0,0,0,1,1, imagesx($image), imagesy($image));
return dechex(imagecolorat($newImg, 0, 0)); // RETURN HEX COLOR
}
// DEMO
foreach(glob('./*.{jpg,png,gif}', GLOB_BRACE) as $i) {
echo '<div style="width:26%;padding:50px;background:#'.
simple_color_thief($i,'f00').
';display:inline-block"><img style="height:200px" src="'.
$i.'"></div>';
}
Source: https://github.com/gaffling/PHP-Simple-Color-Thief/
You should have a look at GD and Image Functions.
There is a similar question on SO about extracting color information from an image with PHP, and it links to this class on github.
You give an image ressouce as argument.
Ex:
$im=imagecreatefromjpeg("path/to/image");
getDominantcolor($im);
NB: This function will little bit slow down your page since it will compare each color of the image to all other color to make the statistic.
It returns rgb value of the dominant color as array
function getDominantcolor($im){
$width=imagesx($im);
$height=imagesy($im);
$colorArr=[];
$comparArr=[];
$colCount=0;
//fixed height
for ($j=0; $j < $height; $j++) {
//fetching color on widths
for ($i=0; $i < $height; $i++) {
$colorArr[]=imagecolorat ( $im ,$i ,$j );
}
}
//fixed height
for ($col=0; $col < count($colorArr); $col++) {
for ($cel=0; $cel < count($colorArr); $cel++) {
if($colorArr[$col]===$colorArr[$cel]){
$colCount+=1;
}
}
$comparArr[]=$colCount;
$colCount=0;
}
foreach ($comparArr as $key => $value) {
if($value===max($comparArr)){
$max_index=$key;
break;
}
}
$rgb=$colorArr[$max_index];
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
return ['r'=>$r,'g'=>$g,'b'=>$b];
}
Though its in javascript but color-thief is best for getting dominant color in image.
https://github.com/lokesh/color-thief

PHP using imageline and XOR

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.

Categories