PHP GD text is not smooth - php

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.

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.

How to make transparent text to jpeg?

Everywhere is talking about adding text on transparent image. I have successfully added text like watermark (so mean transparent text). Can you suggest me how to give opacity 50% ?
Here is code -
$text = "GIF-KING";
$font = "arial.ttf";
$image = imagecreatefromgif('tmpimg/myimage.gif');
$text_color = imagecolorallocate($image, 198, 60, 147);
//imagestring($image,36, 10, 20, $text, $text_color);
imagettftext($image, 30, 0,10, 290, $text_color, $font, $text);
You'd need imagecolorallocatealpha instead of imagecolorallocate,
alpha blending is not available 100%, so take care of error messages.
imagecolorallocatealpha() behaves identically to imagecolorallocate()
with the addition of the transparency parameter alpha.
http://php.net/imagecolorallocatealpha

PHP/GD - transparent background

I want to do the following in PHP in combination with GD. ImageMagick is not an option, unfortunately, but this seems like such a common problem that there has to be a solution, I just can't seem to find it.
I want to create a PNG with a transparent background. Then I want to draw a rectangle on it, copy an image on it, and add some text. One way of doing this is as follows:
$image = ImageCreateTrueColor (800, 600);
imagecolortransparent ($image, 0); //0 is pure black, the default fill color
imagerectangle (...);
//code to copy an image
imagettftext ($image, ...);
imagepng ($image);
This works fine, except that part of the copied image might be black, and/or the text might be black. This then also becomes transparent, which is something I don't want.
imagefill ($image, 0,0, 0x7FFF0000);
imagetransparent ($image, 0x7FFF0000);
The above code is something I found online, which fills it with red, then makes red transparent. Again, this causes all red in the image to become transparent. I could choose a color that is unlikely to occur, but I can't guarantee this.
Is there something I'm missing? Can this be fixed?
Thanks for your replies!
imagecolortransparent is probably not what you want here if you're merging images, as single-colour transparency is nasty.
Instead, try it with a transparent fill mask like so:
<?php
$image = imagecreatetruecolor(100, 100);
// Transparent Background
imagealphablending($image, false);
$transparency = imagecolorallocatealpha($image, 0, 0, 0, 127);
imagefill($image, 0, 0, $transparency);
imagesavealpha($image, true);
// Drawing over
$black = imagecolorallocate($image, 0, 0, 0);
imagefilledrectangle($image, 25, 25, 75, 75, $black);
header('Content-Type: image/png');
imagepng($image);

PHP GD : Can i just fill transparent part?

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);

Adding inner shadow to text

I'm looking for the way to add inner shadow to text using PHP. I'm not looking for a solution, which includes HTML and/or CSS. Image must be generated using only PHP.
For examle: http://i.imgur.com/jYGvM.png
From the text above ('Original') I want to create modify text, so it will look like text at the bottom ('Shadow').
Effect must be achieved using only GD library or Imagemagick, because I can't install new libraries to the server.
One way is to draw your text twice with different colors and a small offset.
Below is the sample code, mainly taken from the php manual, with some modifications to let the shadow appear. The resulting image is here.
Code:
<?php
// Create a 300x100 image
$im = imagecreatetruecolor(300, 100);
$white = imagecolorallocate($im, 0xFF, 0xFF, 0xFF);
$gray = imagecolorallocate($im, 0x55, 0x55, 0x55);
$gray2 = imagecolorallocate($im, 0xDD, 0xDD, 0xDD);
// Make the background red
imagefilledrectangle($im, 0, 0, 299, 99, $gray2);
// Path to our ttf font file
$font_file = './ariblk.ttf';
// the text without shadow
imagefttext($im, 40, 0, 10, 45, $white, $font_file, 'Original');
// the shadow for "Shadow"
imagefttext($im, 40, 0, 10, 89, $gray, $font_file, 'Shadow');
// and the word itself
imagefttext($im, 40, 0, 10, 90, $white, $font_file, 'Shadow');
// Output image to the browser
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
?>

Categories