PHP: Function to change text to PNG image with transparency - php

I am trying to change a section of text into an image. I can't figure out what is wrong with my code and also how to make it transparent. Here is what I have so far:
<?PHP
function fsrep_imageaddress($address, $listingid) {
$font_size = 4;
$width = imagefontwidth($font_size)*strlen($address);
$height = imagefontheight($font_size);
$img = imagecreate($width,$height);
$bg = imagecolorallocate($img, 25, 25, 25);
$color = imagecolorallocate($img, 255, 255, 255);
$len = strlen($address);
$ypos = 0;
for($i=0;$i<$len;$i++){
$xpos = $i * imagefontwidth($font_size);
imagechar($img, $font_size, $xpos, $ypos, $address, $color);
$address = substr($address, 1);
}
imagepng($img, ABSPATH.'wp-content/uploads/fsrep/houses/address-'.$listingid.'.png',100);
imagedestroy($img);
}
fsrep_imageaddress(Just Testing, 12)
?>

Why is it not working?
If you look in the error log, you'll see you need to put "Just Testing" in quotes (thanks #scrowler!) in the function call. Then you'll get an error that imagepng takes a quality level of 0 (no compression) to 9 (max). You have 100! Here, I set it to 5 (medium compression).
imagepng($img, ABSPATH.'wp-content/uploads/fsrep/houses/address-'.$listingid.'.png',5);
How do I set a transparent background?
There's a weird thing with palette images (ie those created with imagecreate). The first colour allocated is set as the background, and can't be transparent - so you need to create a dummy color and then convert it to transparent.
// after this line
$bg = imagecolorallocate($img, 25, 25, 25);
// add this
imagecolortransparent($img, $bg);
Result
I made these changes and changed the text to red (255,0,0) for readability and got this:

Related

Create round png image in PHP using transparency and center a letter in it

I'd like to create profile images for my website. The image should be rounded, a solid background color and a single big letter exactly at the center.
So far I've been able to create a square png image and a letter in it but it's not centered. Due to the fact that different letters have different width I get some letters slightly off-center.
I'm going to implement"round" png images in PHP using transparency.
This is the complete script and should work out of the box. You need Arial.tff if you want to use a custom font but it's not strictly needed.
There is a lookup table with some colors. The single letter get hashed (yeah, pretty stupid I know, but this way it's more flexible as I could pass any string I like) and a color is picked.
<?php
$text = "a";
$posx = 40;
$posy = 150;
$size = 120;
$displaytext = strtoupper($text);
$image = imagecreatetruecolor(200, 200);
// pick a background at random
$binhash = md5($text, true);
$numhash = unpack('N2', $binhash);
$index = abs($numhash[1]) % 16;
$palette = array(
array(0xde,0x5a,0xa4),
array(0xae,0xc6,0xcf),
array(0x96,0x6f,0xd6),
array(0xff,0xb3,0x47),
array(0xff,0x69,0x61),
array(0x77,0xdd,0x77),
array(0x03,0xc0,0x3c),
array(0xcf,0xcf,0xc4),
array(0xc2,0x3b,0x22),
array(0xfd,0xfd,0x96),
array(0x83,0x69,0x53),
array(0x77,0x9e,0xcb),
array(0xb1,0x9c,0xd9),
array(0xb3,0x9e,0xb5),
array(0xf4,0x9a,0xc2),
array(0xff,0xd1,0xdc)
);
$r = $palette[$index][0];
$g = $palette[$index][1];
$b = $palette[$index][2];
$image = imageCreate(200, 200);
imageColorAllocate($image, $r, $g, $b);
$color = imageColorAllocate($image, 255, 255, 255);
$font = 'arial.ttf';
$box = imagettfbbox(200, 0, "ARIAL", $displaytext);
$width = abs($box[2] - $box[0]);
$height = abs($box[5] - $box[1]);
$image = imageCreate(200, 200);
imageColorAllocate($image, $r, $g, $b);
$color = imageColorAllocate($image, 255, 255, 255);
$font = 'arial.ttf';
imagettftext($image, 200, 0, 0 + (200/2 - floor($width/2)), 200, $color, "ARIAL", $displaytext);
header("content-type: image/png");
imagepng($image);
imagedestroy($image);
?>
How can I modify such code in order to:
Have round corner. Shall I create a transparent background and a solid disc at the center?
Have the letter centered, no matter which letter it is
This can help you for centering the letter
<?php
$im = new Imagick(); /* Create a new Imagick object */
$draw = new ImagickDraw(); /* Create an ImagickDraw object */
$draw->setFont('/path/to/font.ttf'); /* Set the font */
var_dump($im->queryFontMetrics($draw, "K")); /* Dump the font metrics*/
?>
Using fontmetrics you can calculate the width and height of a specific letter/text with specific font and you can access the properties.
Hope that will help you.

How to write text to images with different sizes using PHP GD

I'm creating images with different sizes. How can I write text on those images so that the texts always fit to the images?
$text = "some text as example";
$font = "arialbd.ttf"
$fontsize = 26;
offset_x = 0;
offset_y = 0;
$image01 = imagecreate( 1120 , 900 );
$image02 = imagecreate( 400 , 300 );
$image03 = imagecreate( 1120 , 900 );
I know that there is the imagefttext function that can apply text to the images but with that function I can only change the font size to make the text bigger. How can I find out that it fits into my image?
If you are looking to scale the font size so that text string fills the image width, try this.
Using imagettfbbox, determine the current text box width:
$bbox = imagettfbbox($fontsize,0,$fontpath,$string);
$tbwidth = $bbox[2];
Then divide the image width by the $tbwidth to get a factor
$factor = round(($imgwidth / $tbwidth), 0, PHP_ROUND_HALF_DOWN); //ie. 800/240=3
Multiple the $factor by you $fontsize to get an approximate increase.
$newfontsize = $fontsize * $factor; //ie. 12(pt) * 3 = 36
Keep in minds, if you're using GD 2.0, fontsize is in Points and not pixels. Your algorithm is going to calculate the difference between your default font size text box (expressed as a text box width) and the image width.
// Set the content-type
header('Content-Type: image/png');
// Create the image
$im = imagecreatetruecolor(800, 600);
// Create some colors
$white = imagecolorallocate($im, 255, 255, 255);
$grey = imagecolorallocate($im, 128, 128, 128);
$black = imagecolorallocate($im, 0, 0, 0);
imagefill($im, 0, 0, $white);
// The text to draw
$text = 'Testing...';
// Replace path by your own font path
$font_file = 'arial.ttf';
$font_size = '15';
$bbox = imageftbbox($font_size, 0, $font_file, $text);
$width = $bbox[2] - $bbox[6];
$height = $bbox[3] - $bbox[7];
// Add the text
imagettftext($im, $font_size, 0, 10, 20, $black, $font_file, $text);
// Using imagepng() results in clearer text compared with imagejpeg()
imagepng($im);
imagedestroy($im);
I recently came across the same situation with transparent backgrounds but the current examples are either not a solution but clues or a solution that doesn't work, so hereby a combined and working solution if anyone need it.
function imagecreater($width = 600, $height = 600) {
//Create an empty transparent image
$img = imagecreatetruecolor($width, $height);
imagealphablending($img, false);
imagesavealpha($img, true);
$transparent = imagecolorallocatealpha($img, 255, 255, 255, 127);
imagefill($img, 0, 0, $transparent);
//Text information
$text = "some text as example";
$font = "arialbd.ttf"
$fontsize = 26; //default font to be altered later
//simulate a complete text box and get the width
$bbox = imageftbbox($fontsize, 0, $font, $text);
$tbwidth = $bbox[2];
//Calculate different between our transparent image and text box
//I've added a little padding (20px) since the text sometimes crossing the edge..
$factor = (($width - 20) / $tbwidth);
//Alter font size with difference to fit fully image
$newfontsize = $fontsize * $factor;
//Find the horisontal center
$bbox = imageftbbox($newfontsize, 0, $font, $text);
$newheight = ($height / 2) + (($bbox[3] - $bbox[7]) / 2);
//Set Color of text
$color = imagecolorallocate($img, 200, 0, 0);
//Produce our image
imagettftext($img, $newfontsize, 0, 0, $newheight, $color, $font, $text);
//Copy image to file and free the cached image
$target = "testimage.png";
imagepng($img, $target);
imagedestroy($img);
}
As rwhite35 mentioning here, please keep in mind that GD 2.0 write font size is in points and not pixels.
Use the imageftbbox function to get the size of the bounding box of the text. You can then adjust the text size to fit the size of the image exactly.
http://www.php.net/manual/en/function.imageftbbox.php

Empty space getting filled with black after GD imagecopy but only in some scenarios

I am experiencing an issue where I am allowing the user to resize images in a container and then need to create a resulting image that is the size of the container but with the image scaled and adjusted as per the users choices.
So for example say the container is 400 x 200 and the user wants to be able to put in a logo that is 600 x 100 they may wish to shrink the logo so it fits and leave space at the top and bottom. I need to be able to save that as an image that is 400x200 with the appropriate gaps at the top and bottom.
What I have found though is that if the image content (the logo in this example) extends beyond BOTH the top and the right of the container everything is fine OR if it DOESNT extend beyond either it is fine but if it extends beyond one and not the other then I get black fill- or something like that- see examples below...
Below are some examples of the results and this is the code I am using...
$cropped = wp_imagecreatetruecolor( $frame_w, $frame_h);
$backgroundColor = imagecolorallocatealpha($cropped, 0, 0, 0, 127);
//imageantialias( $cropped, true );
//if $img_y or $img_x are negative we need to apply the value to $img_x and $img_y
//if $img_y or $img_x are positive we need to apply the value to $dest_x and $dest_y
$dest_x = strstr($img_x,'-') ? 0 : abs($img_x);//if neg is true = 0 else offset inside
$dest_y = strstr($img_y,'-') ? 0 : abs($img_y);
$img_x = strstr($img_x,'-') ? abs($img_x) : 0;//if neg is true offset outside else 0
$img_y = strstr($img_y,'-') ? abs($img_y) : 0;
$img_w = $img_w > $frame_w ? $frame_w : $img_w;
$img_h = $img_h > $frame_h ? $frame_h : $img_h;
imagecopy( $cropped, $resized, $dest_x, $dest_y, $img_x, $img_y, $img_w, $img_h);
//imagecopymerge( $cropped, $resized, $dest_x, $dest_y, $img_x, $img_y, $img_w, $img_h,100);
//imagecopyresampled( $cropped, $resized, $dest_x, $dest_y, $img_x, $img_y, $frame_w, $frame_h, $img_w, $img_h );
imagefill($cropped, 0, 0, $backgroundColor);//putting this after the copy makes any black borders transparent again unless $resized does not extend beyond both dimensions
Examples
Image does not extend beyond top or beyond right (fine)
Image extends beyond bottom but not right (not fine)
Image extends beyond both (fine)
Image extends beyond right but not bottom (not fine)
Image Extends beyond neither (fine)
I have been literally tearing my hair out trying to fix this and tried every possible combination of imagesavealpha, imagecopymerged, imagecolorallocatealpha, imagealphablending etc I can think of but nothing seems to fix this...
So is this a bug/limitation of GD? Or can someone out there come to my rescue!
I don't know if this will help you, but I had an issue with this earlier today. The box expands but the area was black. Here's my code (which fixes it):
<?php
function createImage($text)
{
// Adds an extra space to fill underline
$text = " $text";
// Adds one line at the end
$text .= "\n";
// Wrap the text to fit the image
$text = wordwrap($text, 40, "\n");
// Count new lines
$newlines = substr_count($text, "\n");
// Count how long to expand
if($newlines == 0)
{
$height = 30;
}
else
{
$height = 30*$newlines-$newlines*5;
}
putenv('GDFONTPATH=' . realpath('.'));
header('Content-Type: image/png');
// Adding underline
$e = explode('<', $text);
for($i=0;$i<count($e);$i++)
{
$e[$i] = implode('̲', str_split($e[$i]));
}
// Creating image
$text = implode(' ', $e);
$im = imagecreatetruecolor(315, $height);
$white = imagecolorallocate($im, 255, 255, 255);
$grey = imagecolorallocate($im, 128, 128, 128);
$black = imagecolorallocate($im, 0, 0, 0);
$purple = imagecolorallocate($im, 97, 26, 139);
imagefilledrectangle($im, 0, 0, 399, $height, $white);
$font = 'arialbd.ttf';
imagettftext($im, 11, 0, 10, 20, $purple, $font, $text);
imagepng($im);
imagedestroy($im);
}
createImage("asbdasddsa");
?>
i think this will happen only for PNG check with other formats
I'm not sure if this is an actual answer since it is basically 'Use ImageMagick' but anyway for those for whom ImageMagick is an option the code below might help them achieve the same thing as I was trying to above... Basically ImageMagick seems far superior to GD, no borders around rotated images, no hassles with transparency, no onwanted black fill, clearer resizing if you are enlarging...
$img_x = -50; //left offset of the image within the frame
$img_y = 50; //top offset of the image within the frame
$img_w = 400; //width of the image to be put in the frame
$img_h = 200; // height of the image to be put in the frame
$angle = 45; //rotation to be applied to the image before it is put into the frame
$frame_w = 300; //width of the frame the image is going into
$frame_h = 300; //height of the frame the image is going into
$img_path = 'path/to/image/file.jpg';
$image = new Imagick( $img_path );
$size = $image->getImageGeometry();
$orig_w = $size['width']; $orig_h = $size['height'];
$image->scaleImage( $img_w, $img_h );
//rotate if necessary
if($angle)
{
$image->rotateImage( new ImagickPixel('none'), $angle );
$size = $image->getImageGeometry();
$img_w = $size['width']; $img_h = $size['height'];
}
//composite into frame
//in imagemagick we create an image that is the size of the frame and make it transparent
$frame = new Imagick();
$frame->newImage($frame_w, $frame_h, new ImagickPixel("none"));
//then we composite the image itself into this with the respective offset values
$frame->compositeImage( $image, Imagick::COMPOSITE_DEFAULT, $img_x, $img_y );
//save it
$destfilename = "{$dir}/{$name}-{$img_suffix}.{$ext}";
$frame->writeImage($destfilename);
$frame->clear();
$frame->destroy();
$image->clear();
$image->destroy();
The above code produces this...yay!

Applying text to png transparency issue PHP

I am trying to write text onto a png, however when I do it puts a dark border around it, I am not sure why.
The original image:
The processed image:
Code:
// Load the image
$im = imagecreatefrompng("admin/public/images/map/order/wally.png");
// If there's an error, gtfo
if(!$im) {
die("");
}
$textColor = imagecolorallocate($im, 68, 68, 68);
$width = imagesx($im);
$height = imagesy($im);
$fontSize = 5;
$text = "AC";
// Calculate the left position of the text
$leftTextPos = ($width - imagefontwidth($fontSize)*strlen($text)) / 2;
// Write the string
imagestring($im, $fontSize, $leftTextPos, $height-28, $text, $textColor);
// Output the image
header('Content-type: image/png');
imagepng($im);
imagedestroy($im);
I've had this issue several times, let me find the answer...
Ok, found something:
imagesavealpha($im, true);
imagealphablending($im, true);
Write that before imagepng.
Yes, saving with alpha is important but loading it is important as well. Your PNG image might have transparency but it is good practice to account for that as well.
You'd need to create true color image, set alpha color and then draw your loaded image with text over it. So something like this:
// create true color image
$img = imagecreatetruecolor($width, $height);
$transparent_color = imagecolorallocatealpha($img, 255, 255, 255, 0);
imagealphablending($img, false);
imagefillrectangle($img, 0, 0, $width, $height, $transparent_color);
imagealphablending($img, true);
// draw previously loaded PNG image
imagecopy($img, $loaded_img, 0, 0, 0, 0, $width, $height);
// draw your text
// save the whole thing
imagesavealpha($img, true);
imagepng($img, $file);

PHP imagettftext always drawing black

Basically when I draw text it's ending up black like this: http://i.stack.imgur.com/z675F.png
Instead of the color I'm allocated in PHP and the function.
Code:
$finalImage = imagecreatefrompng($imageFile);
$logo = imagecreatefrompng($logoImage);
imagecopy($finalImage, $logo, $logoPosition['x'], $logoPosition['y'], 0, 0, imagesx($logo), imagesy($logo));
$font = "arial.ttf";
$fontSize = 10;
$yOffSet = 15;
$white = imagecolorallocate($finalImage, 255, 255, 255);
foreach($pixelArray as $key => $x) {
foreach($valueArray[$key] as $valueText) {
imagettftext($finalImage, $fontSize, 0, $x, $yOffSet, $white, $font, $valueText);
$yOffSet += 15;
}
$yOffSet = 15;
}
if($miscText != null) {
foreach($miscText as $key => $text) {
imagettftext($finalImage, $fontSize, 0, $text['x'], $text['y'], $white, $font, $text['text']);
}
}
imagepng($finalImage,$saveFileName.".png");
imagedestroy($finalImage);
It was working before, but then it just stopped and I have no clue why. It was after I changed the source image (Was generating fine) and I hadn't touched the code. I've tried all sorts of things with changing the colors, but I can't get it to display in anything other then black.
Fixed it by changing imagecolorallocate to imagecolorclosest since I already some white text on a logo I copy in:
// imagecolorallocate....
$white = imagecolorclosest($im, 255, 255, 255);
Have you checked if the imagecolorallocate() function is returning boolean false, as it will if the allocation fails? If the $finalImage .png is 8bit, and your pure white color isn't in the source image's palette, this call will fail. You do say you changed the source image, so this is most likely why it's broken now.
$white = imagecolorallocate($finalImage, 255, 255, 255);
if ($white === FALSE) { // note the === -> strict type comparison
die("Failed to allocate color 255/255/255")
}
The function will also simply return a number representing the color triplets, in this case it would 0xFFFFFF. You can try passing that into the imagegetttftext() call directly, see if that helps.
Use imagecreatetruecolor() to allocate the color:
$width = 500; //whatever width you need
$height = 200; //whatever height you need
$white = imagecolorallocate(imagecreatetruecolor($width, $height), 255, 255, 255);
That worked for me.

Categories