๐ค What are "default" avatars?
When it comes to user-uploaded material, such as avatars, for instance, some users might refrain from uploading one and, in those instances providing a sensible fallback is an appropriate thing to do, generally, you'll find that they're simple, with a plain background, some figure like a silhouette of a person, the applications logo, or an egg. Some will provide a custom fallback with the user's initials, giving their fallbacks some difference between users.
And that is what we're going to be doing right now. ๐คฏ
๐ The requirements
For this, you'll need to be running PHP 7+
compiled with support for FreeType.
--with-freetype-dir=DIR
You will also need to have a .ttf
file handy, for local test use, you can copy one from your systems font storage, where ever that happens to be located. For production use, please grab a legal for commercial use copy.
So let's get started writing some code. โ๏ธ
๐จ Our foundation
Before we get so the good stuff, we have some housekeeping to get done first, so let's get that out of the way and create our new function, which I will name createDefaultAvatar()
.
if (!function_exists('createDefaultAvatar')) {
function createDefaultAvatar()
{
}
}
This will house the majority if not all of our image creation work and manipulation, and I'm sorry to my OOP buddies, but this will break SRP. ๐ฑ
๐ Let's create our canvas
The next step in our function will be to create the image stream that we will be manipulating, and for that, we'll use the imagecreate function, which takes two arguments, the width
and height
in pixels and creates a new palette based image, so let's add that to our function, and pass in our width
and height
as arguments with some default sizes.
function createDefaultAvatar(
int $width = 600,
int $height = 600
) {
$image = @imagecreate($width, $height)
or die("Cannot Initialize new GD image stream");
return $image;
}
And yes, you can type-hint the return value with resource
but what will create issues, since resource
isn't valid return value.
Fatal error: Uncaught TypeError: Return value of createDefaultAvatar() must be an instance of resource, resource returned
๐จ Time to add some color
What would an image be without some colors? To add some color to our image, let's allocate a color with the imagecolorallocate function, and thanks to us using the imagecreate
function, the first call to imagecolorallocate()
will fill our background color.
So let's add that section to our function, we will call this function twice, with some default colors added into our arguments.
function createDefaultAvatar(
...,
array $bgColor = [0, 0, 0],
array $textColor = [255, 255, 255]
) {
...
imagecolorallocate($image, $bgColor[0], $bgColor[1], $bgColor[2]);
$fontColor = imagecolorallocate($image, $textColor[0], $textColor[1], $textColor[2]);
return $image;
}
Here we are setting the default $bgColor
to black and our $textColor
to white.
๐๏ธโโ๏ธ Time for some heavy lifting
Now we'll get into the biggest and most difficult part of this function, getting our text to center both vertically and horizontally, to do that we'll need to grab the bounding box of our TrueType text using imagettfbbox, which will return an array of all four points our text bounding box.
And to do that we will need to pass in our font size, the path to our TrueType file, and our text.
function createDefaultAvatar(
...
string $text = 'DEV',
int $fontSize = 140,
string $font = './arial.ttf'
) {
...
$textBoundingBox = imagettfbbox($fontSize, 0, $font, $text);
return $image;
}
The second argument is the angle of our text, we don't care about that.
The next part of this step is to calculate the new $x
and $y
coordinates of our text, so let's add this after our imagettfbbox
function call.
$y = abs(ceil(($height - $textBoundingBox[5]) / 2));
$x = abs(ceil(($width - $textBoundingBox[2]) / 2));
This will calculate the position by dividing our bounding box in half to get the middle, and rounding up the division between that and our image height or width, then we get the absolute value of that.
NOTE:
I added the abs
function after some experiment, with just ceil
the text was sometimes of by a pixel give or take.
You might need to experiment with the bounding box values to get the perfect fit for your font file.
โ๏ธ Time to write our text
The last step in our function is to write our text to our image, all we've done up till this point is to create our image, set some colors, and calculated where out text should be positioned, now we will use imagettftext to write the text to our image.
So before we return our image, let's write to it, using our new coordinates, our $fontColor
, $font
, and $text
.
function createDefaultAvatar(
...
) {
...
imagettftext($image, $fontSize, 0, $x, $y, $fontColor, $font, $text);
return $image;
}
As above, the 0
in this case is our angle and we don't care about those.
๐ Finished function
After switching the arguments around to better fit the usage of the function, the final function will look something like this.
if (!function_exists('createDefaultAvatar')) {
function createDefaultAvatar(
string $text = 'DEV',
array $bgColor = [0, 0, 0],
array $textColor = [255, 255, 255],
int $fontSize = 140,
int $width = 600,
int $height = 600,
string $font = './arial.ttf'
) {
$image = @imagecreate($width, $height)
or die("Cannot Initialize new GD image stream");
imagecolorallocate($image, $bgColor[0], $bgColor[1], $bgColor[2]);
$fontColor = imagecolorallocate($image, $textColor[0], $textColor[1], $textColor[2]);
$textBoundingBox = imagettfbbox($fontSize, 0, $font, $text);
$y = abs(ceil(($height - $textBoundingBox[5]) / 2));
$x = abs(ceil(($width - $textBoundingBox[2]) / 2));
imagettftext($image, $fontSize, 0, $x, $y, $fontColor, $font, $text);
return $image;
}
}
Calling our new function createDefaultAvatar();
without any arguments will create an image looking like this.
Now we can use this function to create user initial avatars by simply passing in new initials into our function.
createDefaultAvatar("KH")
๐ฎ More usages.
Why not use this more PHP functions and return the image directly in the browser? We can do that too. ๐
$img = createDefaultAvatar();
header("Content-Type: image/png");
imagepng($img);
imagedestroy($img);
Now when you visit your file in the browser, PHP will render the image in the browser, you can also save the image by providing a path or stream as the second argument to imagepng.
๐ Parting words
So, is this production-ready? Can it be improved? I would say maybe to the first and absolutely to the later.
This is just a tutorial, a proof-of-concept so to speak.
I would break this up into its own class, maybe a service class, that would create, store and give back the location path to be stored in the database for future reference.
But I will leave that up to you, hope you enjoyed it, thanks for reading and goodbye. ๐
TL;DR
Source code:
Top comments (1)
really nice peace of code , well document on the post, thanx for sharing knowledge.