How to create a cuboid with PHP

In this short tutorial, I'll show you how to create a three-dimensional rectangle with the PHP GD image library. An example of what we'll be creating:


Let's get started.

First, we'll add some checks to see if GD library is installed with imagewebp. We will also validate the dimensions so that they are not out of range.

The code to create the image stream or our canvas also checks if GD library is installed. This is perhaps a little redundant because if you have a imagewebp function, chances are that you will also have the library installed.

private const MINIMUM_DIMENSION = 5;
private const MAXIMUM_DIMENSION = 250;

/**
* @throws Exception
*/
public function execute(int $length, int $width, int $height): string
{
     if (!function_exists('imagewebp')) {
        throw new Exception('imagewebp is not a function. Is the GD library installed with the webP format?');
     }

     if ($this->isOutsideRange($length) || $this->isOutsideRange($width) || $this->isOutsideRange($height)) {
        throw new Exception('The dimensions need to be each between ' . self::MINIMUM_DIMENSION .
                                 ' and ' . self::MAXIMUM_DIMENSION .' cm.');
     }

     $halfWidth = intval(round($width / 2));
     $image = @imagecreatetruecolor($length + $halfWidth + 2, $height + $halfWidth + 2)
                 or die('Unable to create image. Please ensure that the GD library is installed and working correctly.');

     ...
}     

private function isOutsideRange(int $number): bool
{
     return $number < self::MINIMUM_DIMENSION || $number > self::MAXIMUM_DIMENSION;
}

Notice that we'll start with a canvas that will be slightly wider and taller than a simple presentation of width X height. We need to take into account the extra space we'll need to make the rectangle 3d.
We also want the image to have black lines (= rectangleColor/RGB: 0,0,0) on a transparent background:

imagesavealpha($image, true);
$backgroundColor = imagecolorallocatealpha($image, 0, 0, 0, 127);
$rectangleColor = imagecolorallocate($image, 0, 0, 0);
imagefill($image, 0, 0, $backgroundColor);

In order to simplify the code to draw two rectangles:

$rectangleFront = $this->getRectanglePoints(0, $halfWidth, $length, $height);        
$rectangleBack = $this->getRectanglePoints($rectangleFront->x1 + $halfWidth, $rectangleFront->y1 - $halfWidth, $length, $height);

imagerectangle($image, $rectangleFront->x1, $rectangleFront->y1, $rectangleFront->x2, $rectangleFront->y2, $rectangleColor);
imagerectangle($image, $rectangleBack->x1, $rectangleBack->y1, $rectangleBack->x2, $rectangleBack->y2, $rectangleColor);

we added a simple private function for this:

private function getRectanglePoints(int $x, int $y, int $length, int $height): object
{
    return (object) [
         'x1' => $x,
         'y1' => $y,
         'x2' => $x + $length,
         'y2' => $y + $height,
   ];
}

To connect the dots:

imageline($image, $rectangleFront->x1, $rectangleFront->y1, $rectangleBack->x1, $rectangleBack->y1, $rectangleColor);
imageline($image, $rectangleFront->x1, $rectangleFront->y2, $rectangleBack->x1, $rectangleBack->y2, $rectangleColor);

imageline($image, $rectangleFront->x2, $rectangleFront->y1, $rectangleBack->x2, $rectangleBack->y1, $rectangleColor);
imageline($image, $rectangleFront->x2, $rectangleFront->y2, $rectangleBack->x2, $rectangleBack->y2, $rectangleColor);

and finally capture and return the dynamic webp image and destroy it to save some memory on the server:

ob_start();

imagewebp($image);
imagedestroy($image);

return ob_get_clean();

Here is the full code:

namespace App\MyScape\Scape\Actions;

use Exception;

class GetDimensionsImageAction
{
    private const MINIMUM_DIMENSION = 5;
    private const MAXIMUM_DIMENSION = 250;

    /**
     * @throws Exception
     */
    public function execute(int $length, int $width, int $height): string
    {
        if (!function_exists('imagewebp')) {
            throw new Exception('imagewebp is not a function. Is the GD library installed with the webP format?');
        }

        if ($this->isOutsideRange($length) || $this->isOutsideRange($width) || $this->isOutsideRange($height)) {
            throw new Exception('The dimensions need to be each between ' . self::MINIMUM_DIMENSION .
                                        ' and ' . self::MAXIMUM_DIMENSION .' cm.');
        }

        $halfWidth = intval(round($width / 2));
        $image = @imagecreatetruecolor($length + $halfWidth + 2, $height + $halfWidth + 2)
                 or die('Unable to create image. Please ensure that the GD library is installed and working correctly.');

        imagesavealpha($image, true);
        $backgroundColor = imagecolorallocatealpha($image, 0, 0, 0, 127);
        $rectangleColor = imagecolorallocate($image, 0, 0, 0);
        imagefill($image, 0, 0, $backgroundColor);

        $rectangleFront = $this->getRectanglePoints(0, $halfWidth, $length, $height);
        $rectangleBack = $this->getRectanglePoints($rectangleFront->x1 + $halfWidth, $rectangleFront->y1 - $halfWidth, $length, $height);

        imagerectangle($image, $rectangleFront->x1, $rectangleFront->y1, $rectangleFront->x2, $rectangleFront->y2, $rectangleColor);
        imagerectangle($image, $rectangleBack->x1, $rectangleBack->y1, $rectangleBack->x2, $rectangleBack->y2, $rectangleColor);

        imageline($image, $rectangleFront->x1, $rectangleFront->y1, $rectangleBack->x1, $rectangleBack->y1, $rectangleColor);
        imageline($image, $rectangleFront->x1, $rectangleFront->y2, $rectangleBack->x1, $rectangleBack->y2, $rectangleColor);

        imageline($image, $rectangleFront->x2, $rectangleFront->y1, $rectangleBack->x2, $rectangleBack->y1, $rectangleColor);
        imageline($image, $rectangleFront->x2, $rectangleFront->y2, $rectangleBack->x2, $rectangleBack->y2, $rectangleColor);

        ob_start();

        imagewebp($image);
        imagedestroy($image);

        return ob_get_clean();
    }

    private function isOutsideRange(int $number): bool
    {
        return $number < self::MINIMUM_DIMENSION || $number > self::MAXIMUM_DIMENSION;
    }

    private function getRectanglePoints(int $x, int $y, int $length, int $height): object
    {
        return (object) [
            'x1' => $x,
            'y1' => $y,
            'x2' => $x + $length,
            'y2' => $y + $height,
        ];
    }
}

That's it. I advise you to cache the images and perhaps avoid hotlinking to saveguard your precious server time.