PHP GD : Can i just fill transparent part? - php

There is an image which has transparent area. (png image)
Now, while doing a imagecopy, can we just fill that transparent area?
Imagemagick can do this easily. Is that possible in php gd?

A layered approach via imagecopymerge() is one route. The concept is to merge your source image onto a new image, with a pre-set background image, which will show through the source image's transparency once merged.
//create main image - transparent, with opaque red square in middle
$img = imagecreate(60, 60);
$white = imagecolorallocate($img, 255, 255, 255);
imagecolortransparent($img, $white); //make background transparent
$red = imagecolorallocate($img, 255, 0, 0);
imagefilledrectangle($img, imagesx($img) / 4, imagesy($img) / 4, imagesx($img) - (imagesx($img) / 4), imagesy($img) - (imagesy($img) / 4), $red);
//create new image, with pre-filled background, then merge first image across
$img2 = imagecreate(60, 60);
$blue = imagecolorallocate($img2, 0, 0, 255);
imagecopymerge($img2, $img, 0, 0, 0, 0, imagesx($img), imagesy($img), 100);
//output
imagepng($img2);
So the first image creates a transparent image (the white) with a red square in the middle. The second image is simply a blue fill.Merge the two, and the blue shows through the transparent part of the first image, so our red square now sits on the blue fill. Effectively, we've filled the transparent part.
Here's the three states in sequence.

There is nothing to 'fill' where there is transparency. Transparency in a png (or gif) is not the absence of a color, but a single color specifically marked to be shown as transparent. Therefore you want to remove that marker.
Take a look at the php gds function 'imagecolortransparent':

Nope, you can't.
Instead that, you can try to create a copy from a colored rectangle. This code worked for me:
$input = imagecreatefrompng($file_input);
list($width, $height) = getimagesize($file_input);
$output = imagecreatetruecolor($width, $height);
$white = imagecolorallocate($output, 255, 255, 255);
imagefilledrectangle($output, 0, 0, $width, $height, $white);
imagecopy($output, $input, 0, 0, 0, 0, $width, $height);
imagepng($output, $file_output);

Related

How to make a color transparent in gd lib after merging images?

I am using gd lib to merge several images, but I'm having problems with the transparency. First I merge several images which each have a transparent background (works fine). Then I want to put another picture on top which consists of three parts: one part that I want to keep, a transparent part where the images below should show and one part in a color (e.g. green #00ff00) which is supposed to become transparent as well after merging. The images are pixel images, so I only want #0f0 to become transparent, none other color.
Here is an image of the result of the code.
The first picture shows the merged images ("circle" & "cloud").
The second picture shows the "hat" which is put on top of the merged images.
The third picture shows the result I want to achieve.
The fourth picture is what I actually get.
Whatever I do, I can't seem to find the solution. I'd be grateful for your help!
header("Content-type: image/png");
$img = imagecreatetruecolor(200, 200);
//make an image with transparent background
$transparency = imagecolorallocatealpha($img, 0, 0, 0, 127);
imagefill($img, 0, 0, $transparency);
imagesavealpha($img, true);
$circle = imagecreatefrompng("testcircle.png"); //black circle
$cloud = imagecreatefrompng("testcloud.png"); //brown cloud
$hat = imagecreatefrompng("testhat.png"); //blue hat with green area
imagecopy($img, $circle, 0, 0, 0, 0, 200, 200);
imagealphablending($img,true);
imagecopy($img, $cloud, 0, 0, 0, 0, 200, 200);
imagealphablending($img,true);
$green = imagecolorallocate($hat, 0, 255, 0);
imagecolortransparent($hat, $green);
imagecopy($img, $hat, 0, 0, 0, 0, 200, 200);
imagealphablending($img,true);
/* //With this the green area just keeps being green as in the second picture
$green = imagecolorallocate($img, 0, 255, 0);
imagecolortransparent($img, $green);
imagecopy($img, $hat, 0, 0, 0, 0, 200, 200);
imagealphablending($img,true);
*/
imagepng($img);
imagedestroy($img);
After searching for a long time, I've found the solution for my problem. I hope it will help if someone has the same question as me in future.
$green = imagecolorallocate($img, 0, 255, 0);
imagecopy($img, $hat, 0, 0, 0, 0, 200, 200);
imagecolortransparent($img, $green);
imagefill($img,0,0,imagecolorallocatealpha($img, 0, 0, 0, 127)); //this line does the trick
First of all I define green as a color. Then I copy the "hat" onto the picture and make the color transparent. Then comes the trick about filling the picture and that makes the green area transparent again.
(I found the solution in a german forum).
I noticed that this code only makes the first green area transparent though. If there are two seperated areas (or even more), (at least) one will stay green. So while this is a solution that works for me, there might be one out there that is even better.

PHP merging two images creates a pink shade

I am trying to merge two images using PHP code below:
$image1=imagecreatefrompng($url1);
$image2=imagecreatefrompng($url2);
$final = imagecreatetruecolor($w, $h);
$backgroundColor = imagecolorallocate($final, 255, 255, 255);
imagefill($final, 0, 0, $backgroundColor);
imagecopy($final, $image1, 0,0,0,0,$w,$h);
imagecopy($final, $image2, 0,0,0,0,$w,$h);
After merging, I get a pink shade on the generated images. Please help. How can I resolve it?
Original images:
Resulting merged image:
Your target image is GIF, which is limited to a 256 colour palette. Try exporting as JPG or PNG and you'll probably get better colour fidelity.
I have tried your code using your image link
and its works well and generates appropriate png
For your reference
$url1 = 'http://i.stack.imgur.com/kDYTM.png';
$url2 ='http://i.stack.imgur.com/MKTcb.png';
$image1=imagecreatefrompng($url1);
$image2=imagecreatefrompng($url2);
$final = imagecreatetruecolor(275, 275);
$backgroundColor = imagecolorallocate($final, 255, 255, 255);
imagefill($final, 0, 0, $backgroundColor);
imagecopy($final, $image1, 0,0,0,0,275,275);
imagecopy($final, $image2, 0,0,0,0,275,275);
header('Content-type:image/png');
imagepng($final);
For gif image you can replace last two line with
header('Content-type:image/gif');
imagegif($final);

Create a tiled image with offset

In the process of creating a tiled image I'd like to set an offset (so that the tile doesn't start at 0, 0) but when I provide what I'd expect to give me the correct image, it's not rendered correctly.
I'm setting the tile using imagesettile($image, $tile); but when I go to draw it (using imagefilledrectangle($image, 10, 10, 300, 300, IMG_COLOR_TILED);), I get an image as though it was tiled from 0, 0 (with the top & left 10 pixels black) instead of it being tiled from 10, 10.
Any ideas as to how I can get it tiled from 10, 10 or do I have to create another tiled image and copy it across?
In the end I had to create a new image which was tiled and copy it in. The final code is along the lines of:
$transparent = imagecolorallocatealpha($background_image, 255, 255, 255, 127);
$tiled_image = imagecreatetruecolor($width, $height);
imagefill($tiled_image, 0, 0, $transparent);
imagesettile($tiled_image, $tile);
imagefilledrectangle($tiled_image, 0, 0, $width, $height, IMG_COLOR_TILED);
imagecopyresampled($image, $tiled_image, $sx, $sy, 0, 0, $ex, $ey, $width, $height);

PHP GD text is not smooth

Screenshot of problem:
I'm trying to get the same font quality such as Font Squirrel's sample fonts widget, but the font keeps coming out rough. It's smooth in Photoshop. Note: the "The lazy dog" part isn't being bolded by me, its doing it by itself.
Here's the PHP:
<?php
putenv('GDFONTPATH=' . realpath('.'));
$font = $_GET['font'] . '.ttf';
$text = 'The Quick Brown Fox Jumps over the Lazy Dog';
// Create the image
function imageCreateTransparent($x, $y) {
$imageOut = imagecreate($x, $y);
$colourBlack = imagecolorallocate($imageOut, 0, 0, 0);
imagecolortransparent($imageOut, $colourBlack);
return $imageOut;
}
$image = imageCreateTransparent(600, 800);
// Create some colors
$white = imagecolorallocate($image, 255, 255, 255);
$grey = imagecolorallocate($image, 128, 128, 128);
$black = imagecolorallocate($image, 0, 0, 0);
imagefilledrectangle($image, 0, 0, 399, 29, $white);
// Add the text
imagettftext($image, 20, 0, 10, 20, $black, $font, $text);
imagepng($image);
imagealphablending($image, true);
imagedestroy($image);
?>
HTML: <img src="fontgen.php?font=Aller_Rg" alt="" />
How can I get that high quality result for the font?
You've only set part of the background to be white, the rest of it is transparent.
When the font is drawn over a white background, the black text is anti-aliased so that it looks smooth, which results in the pixels around the font being drawn as a blend between the two colours, which also makes the font look smaller.
On the right hand side there is no background colour so the anti-aliasing is not working properly. Instead of blending between the font colour and the background colour, the drawing algorithm is using the original font colour for any pixel that is even partly covered by a letter.
This makes the letters look 'bold' as the edge pixels are now black, instead of shades of grey.
The way to fix this properly is to use an image that has a proper background colour, even if that background colour is transparent. This makes the image library use a proper alpha-channel (which is the only sensible way of doing alpha blending) rather than using an indexed based alpha, where only one 'colour' is transparent and all the others are fully opaque.
$font = '../../fonts/Aller_Rg.ttf';
$text = 'The Quick Brown Fox Jumps over the Lazy Dog';
// Create the image
function imageCreateTransparent($x, $y) {
$imageOut = imagecreatetruecolor($x, $y);
$backgroundColor = imagecolorallocatealpha($imageOut, 0, 0, 0, 127);
imagefill($imageOut, 0, 0, $backgroundColor);
return $imageOut;
}
$image = imageCreateTransparent(600, 800);
// Create some colors
$white = imagecolorallocate($image, 255, 255, 255);
$grey = imagecolorallocate($image, 128, 128, 128);
$black = imagecolorallocate($image, 0, 0, 0);
imagefilledrectangle($image, 0, 0, 399, 29, $white);
//// Add the text
imagettftext($image, 20, 0, 10, 20, $black, $font, $text);
//imagealphablending($image, true); //not needed as we created the image with alpha
imagesavealpha($image, true);
//imagepng($image, '../../var/log/wtf5.png');
imagepng($image);
imagedestroy($image);
This will make the font size be right as the anti-aliasing will work correctly* and the image will be transparent where appropriate e.g. the image created with the code above, shown over a red background.
The bits of the image that have a white background are white, the bits of the image that are transparent let the red colour come through, and the text is anti-aliased correctly to both.
*assuming that you want to anti-alias to what the background colour was set to, which is not always the case but probably is here.
I suspect it's because you're making the background explicitly white only in the left 400 px. To the right of that it's probably still transparent and has some side-effects. The r is the first letter that starts beyond the white background you created earlier.

Merge images with PHP

I have written a code for merge two images.
My code is:
$rnd = rand("99000", "99999");
$dst_path = "/home/maxioutl/public_html/images/urunler/";
$dst_file_name = "tresim-{$rnd}.jpg";
$dst_file = $dst_path.$dst_file_name;
$dst = imagecreatetruecolor(250, 375);
imagefill($dst, 0, 0, imagecolorallocate($dst, 255, 255, 255));
$src = imagecreatefromjpeg("http://www.goldstore.com.tr/upload/product/raw/3.72925.0332.JPG");
imagecopymerge($dst, $src, 40, 60, 0, 0, 250, 375, 100);
imagejpeg($dst, $dst_file, 90);
Result:
Black background. Where is it?
It's the imagecopymerge($dst, $src, 40, 60, 0, 0, 250, 375, 100); statement that's doing it.
You're passing it the dimensions 250x375, which isn't the watch's actual dimensions. Therefore the merge bounding box continues on and it uses black. You can see this easily if you comment it out because you'll get your white square from the fill like you were expecting.
you need to get the exact dimensions of your watch graphic (i.e. through getimagesize) and pass those to imagecopymerge so it cuts it exactly when it merges.
$arrSize = getimagesize($originalFile);
imagecopymerge($dst, $src, 40, 60, 0, 0, $arrSize[0], $arrSize[1], 100);
The code you wrote superimposes the images. It does not remove the white pixels from the image with the watch.
They are basically overlapped.
You should cycle through both image dimensions and replace each *white pixel with a black pixel or a transparent pixel.
*white pixel may not necessarily mean rgb(255,255,255) you can choose to treat all pixels with rgb(>235,>235,>235) as being "white".
Function imagecreatetruecolor creates completely black image
Taken from here :
imagecreatetruecolor() returns an image identifier representing a
black image of the specified size.

Categories