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);
?>
Related
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!
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.
So I'm using a method for re-sizing images that I came across on here the other day and it works great for the initial image it processes but I use the process a second time to create a smaller image to use for a thumb nail. When this second thumb nail is created it comes out with a black background where it should be transparent. I know this is a common problem as I have seen plenty of threads on here with similar complaints. When I was looking last night in the php error logs it was saying that imagecolorat was trying to hit pixels which were out of bounds.....
PHP Notice: imagecolorat(): 0,28 is out of bounds in C:\inetpub\
At least I know whats happening but what I need to know now is how to fix it. Its really strange that for the larger copy of the same image I dont get this error at all and it works just fine producing a nice copy of the larger uploaded copy. Heres the code that Im using to resize everything:
$image_source = imagecreatefromstring($markericon); //original image
$imgHead = "image/jpeg"; //tag for image to be pulled later. images go in are png's
//code to make sure image is never larger than certain size
$image_width = imagesx($image_source);
$image_height = imagesy($image_source);
if($image_width>$max_upload_large_side || $image_height >$max_upload_large_side){
$proportionslarge = $image_width/$image_height;
if($image_width>$image_height){
$new_large_width = $max_upload_large_side;
$new_large_height = round($max_upload_large_side/$proportionslarge);
}
else{
$new_large_height = $max_upload_large_side;
$new_large_width = round($max_upload_large_side*$proportionslarge);
}
$new_large_image = imagecreatetruecolor($new_large_width , $new_large_height);
//code used to retain image transparency
//over write alpha chanel of image destination
imagealphablending($new_large_image, false); // Overwrite alpha
imagesavealpha($new_large_image, true);
// Create a separate alpha channel to blend images with
$alpha_image = imagecreatetruecolor($image_width, $image_height);
imagealphablending($alpha_image, false); // Overwrite alpha
imagesavealpha($alpha_image, true);
//copy data at every pixel in image
for ($x = 0; $x < $image_width; $x++) {
for ($y = 0; $y < $image_height; $y++) {
$alpha = (imagecolorat($image_source, $x, $y) >> 24) & 0xFF;
$color = imagecolorallocatealpha($alpha_image, 0, 0, 0, $alpha);
imagesetpixel($alpha_image, $x, $y, $color);
}
}
// Resize image to destination, using gamma correction
imagegammacorrect($image_source, 2.2, 1.0);
imagecopyresampled($new_large_image, $image_source, 0, 0, 0, 0, $new_large_width, $new_large_height, $image_width, $image_height);
imagegammacorrect($new_large_image, 1.0, 2.2);
// Resize alpha channel
$alpha_resized_image = imagecreatetruecolor($new_large_width, $new_large_height);
imagealphablending($alpha_resized_image, false);
imagesavealpha($alpha_resized_image, true);
imagecopyresampled($alpha_resized_image, $alpha_image, 0, 0, 0, 0, $new_large_width, $new_large_height, $image_width, $image_height);
// Copy alpha channel back to resized image
for ($x = 0; $x < $new_large_width; $x++) {
for ($y = 0; $y < $new_large_height; $y++) {
$alpha = (imagecolorat($alpha_resized_image, $x, $y) >> 24) & 0xFF;
$rgb = imagecolorat($new_large_image, $x, $y);
$r = ($rgb >> 16 ) & 0xFF;
$g = ($rgb >> 8 ) & 0xFF;
$b = $rgb & 0xFF;
$color = imagecolorallocatealpha($new_large_image, $r, $g, $b, $alpha);
imagesetpixel($new_large_image, $x, $y, $color);
}
}
// end of first run//
ob_start(); // Start capturing stdout.
imagePNG($new_large_image);
$lBinaryThumbnail = ob_get_contents(); // the raw jpeg image data.
ob_end_clean(); // Dump the stdout so it does not screw other output.
$lBinaryThumbnail = addslashes($lBinaryThumbnail);
imagedestroy($new_large_image);
} else $lBinaryThumbnail = $imgData;
//start of second image run
if($image_width>$max_upload_small_side || $image_height >$max_upload_small_side){
$proportionssmall = $image_width/$image_height;
if($image_width>$image_height){
$new_small_width = $max_upload_small_side;
$new_small_height = round($max_upload_small_side/$proportionssmall);
}
else{
$new_small_height = $max_upload_small_side;
$new_small_width = round($max_upload_small_side*$proportionssmall);
}
$new_small_image = imagecreatetruecolor($new_small_width , $new_small_height);
//////////////////////////////////////////////////////////////////////////////////
//over write alpha chanel of image destination
imagealphablending($new_small_image, false); // Overwrite alpha
imagesavealpha($new_small_image, true);
// Create a separate alpha channel to blend images with
$alpha_image = imagecreatetruecolor($image_width, $image_height);
imagealphablending($alpha_image, false); // Overwrite alpha
imagesavealpha($alpha_image, true);
//copy data at every pixel in image
for ($x = 0; $x < $image_width; $x++) {
for ($y = 0; $y < $image_height; $y++) {
$alpha = (imagecolorat($image_source, $x, $y) >> 24) & 0xFF;
$color = imagecolorallocatealpha($alpha_image, 0, 0, 0, $alpha);
imagesetpixel($alpha_image, $x, $y, $color);
}
}
// Resize image to destination, using gamma correction
imagegammacorrect($image_source, 2.2, 1.0);
imagecopyresampled($new_small_image, $image_source, 0, 0, 0, 0, $new_small_width , $new_small_height, $image_width, $image_height);
imagegammacorrect($new_small_image, 1.0, 2.2);
// Resize alpha channel
$alpha_resized_image = imagecreatetruecolor( $image_width, $image_height);
imagealphablending($alpha_resized_image, false);
imagesavealpha($alpha_resized_image, true);
imagecopyresampled($alpha_resized_image, $alpha_image, 0, 0, 0, 0, $new_small_width ,$new_small_height, $image_width, $image_height);
// Copy alpha channel back to resized image
for ($x = 0; $x < $new_small_width; $x++) {
for ($y = 0; $y < $new_small_height; $y++) {
$alpha = (imagecolorat($alpha_resized_image, $x, $y) >> 24) & 0xFF;
$rgb = imagecolorat($new_small_image, $x, $y); //this is the line that throws the error first and gives a out of bounds related error.
$r = ($rgb >> 16 ) & 0xFF;
$g = ($rgb >> 8 ) & 0xFF;
$b = $rgb & 0xFF;
$color = imagecolorallocatealpha($new_small_image, $r, $g, $b, $alpha);
imagesetpixel($new_small_image, $x, $y, $color);
}
}
// end of new code //
//imagecopyresampled($new_small_image, $image_source, 0, 0, 0, 0, $new_small_width, $new_small_height, $image_width, $image_height);
ob_start(); // Start capturing stdout.
imagePNG($new_small_image);
$sBinaryThumbnail = ob_get_contents(); // the raw jpeg image data.
ob_end_clean(); // Dump the stdout so it does not screw other output.
$sBinaryThumbnail = addslashes($sBinaryThumbnail);
imagedestroy($new_small_image);
} else $sBinaryThumbnail = $lBinaryThumbnail;
imagedestroy($image_source);
Like I said everything works fine for the first run but for some reason on the second run it farts and throws a out of bounds error. it starts at 0,28 and goes on until the end of the loop process at 50,50
I figured it out :) I took the code I had up above that created the alpha correct copy and turned it all into its own function and now it works just fine.
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.
$im = imagecreatefrompng('./test.png');
$white = imagecolorallocate($im, 255, 255, 255);
imagecolortransparent($im, $white);
This code is fine for removing pure white from an image, but I what I want to do is convert all colors to alpha percentages. For example medium gray would be 50% transparent black. So an image that was medium gray would show the image behind it, if placed on top.
Is this possible using PHP or an extension?
I just wrote and tested this script for you.
$imfile = './test.png';
$origim = imagecreatefrompng($imfile);
$im_size = getimagesize($imfile);
$im = imagecreatetruecolor($im_size[0], $im_size[1]);
imagealphablending($im, false);
imagesavealpha($im, true);
for ($x = 0; $x < $im_size[0]; ++$x){
for ($y = 0; $y < $im_size[1]; ++$y){
$rgb = imagecolorat($origim,- $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$color = imagecolorallocatealpha($im, 0, 0, 0, intval(($r+$g+$b)/3/255*127));
imagesetpixel($im, $x, $y, $color);
}
}
It may be a bit slow on large images, but it works just like you want it to. =)
Hope this answer is Acceptable. Good luck.