Creating default user initial avatars in PHP 7 🤘😎
Tags: php, showdev, tutorial, webdev
Published: 2020-08-22 11:12:26

# 🤔 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]**.

```bash
--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()`.

```php
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 <abbr title="object-oriented programming">OOP</abbr> buddies, but this will break <abbr title="single-responsibility principle">**SRP**</abbr>. 😱

---

### 🌄 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.

```php
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.

```bash
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.

```php
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**.

```php
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.

```php
$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`.

```php
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.

```php
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.

![image with a black background and white text saying dev](https://i.imgur.com/ofsdFSQ.png)

Now we can use this function to create user initial avatars by simply passing in new initials into our function.

![image with a black background and white text saying k h](https://i.imgur.com/ZFYL2pi.png)

```php
createDefaultAvatar("KH")
```

---

### 😮 More usages.

Why not use this more PHP functions and return the image directly in the browser? We can do that too. 🙌

```php
$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:

{% github thinkverse/create-avatar no-readme %}

![showing rendering default avatar in browser](https://i.gyazo.com/bc91bfc66651fb64ff1679c07aebc9c0.gif)

[freetype]: https://www.php.net/manual/en/function.imagettftext.php#refsect1-function.imagettftext-notes
[imagecreate]: https://www.php.net/manual/en/function.imagecreate.php
[imagecolorallocate]: https://www.php.net/manual/en/function.imagecolorallocate.php
[imagettftext]: https://www.php.net/manual/en/function.imagettftext.php
[imagettfbbox]: https://www.php.net/manual/en/function.imagettfbbox.php
[imagepng]: https://www.php.net/manual/en/function.imagepng.php