From 854987bd440565a2f73c7965c7d18cedd3f8fcfb Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Fri, 7 Jan 2022 19:53:31 -0500 Subject: [PATCH] Create image builder class to simplify creating placeholder images --- src/Ion/Exception/ImageCreationException.php | 26 +++ src/Ion/ImageBuilder.php | 167 +++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 src/Ion/Exception/ImageCreationException.php create mode 100644 src/Ion/ImageBuilder.php diff --git a/src/Ion/Exception/ImageCreationException.php b/src/Ion/Exception/ImageCreationException.php new file mode 100644 index 00000000..c9b01537 --- /dev/null +++ b/src/Ion/Exception/ImageCreationException.php @@ -0,0 +1,26 @@ + + * @copyright 2015 - 2021 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 5.2 + * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\Ion\Exception; + +use RuntimeException; + +/** + * Exception for bad configuration + */ +class ImageCreationException extends RuntimeException { + +} \ No newline at end of file diff --git a/src/Ion/ImageBuilder.php b/src/Ion/ImageBuilder.php new file mode 100644 index 00000000..86021d8c --- /dev/null +++ b/src/Ion/ImageBuilder.php @@ -0,0 +1,167 @@ + + * @copyright 2015 - 2021 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 5.2 + * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\Ion; + +use GdImage; + +use Aviat\Ion\Exception\ImageCreationException; + +/** + * A wrapper around GD functions to create images + * + * @property GdImage|false|null $img + */ +class ImageBuilder { + private GDImage|false|null $_img; + + private int $fontSize = 10; + + private function __construct(private int $width=200, private int $height=200 ) + { + $this->_img = imagecreatetruecolor($this->width, $this->height); + } + + public function __destruct() + { + $this->cleanup(); + } + + private function getImg(): GdImage + { + if ($this->_img instanceof GdImage) + { + return $this->_img; + } + + throw new ImageCreationException('Invalid GD object'); + } + + public static function new(int $width=200, int $height=200): self + { + $i = new self($width, $height); + if ($i->_img === FALSE) + { + throw new ImageCreationException('Could not create image object'); + } + + return $i; + } + + public function setFontSize(int $size): self + { + $this->fontSize = $size; + + return $this; + } + + public function enableAlphaBlending(bool $enable): self + { + $ab = imagealphablending($this->getImg(), $enable); + if ( ! $ab) + { + throw new ImageCreationException('Failed to toggle image alpha blending'); + } + + return $this; + } + + public function addCenteredText(string $text, int $red, int $green, int $blue, int $alpha=-1): self + { + // Create the font color + $textColor = ($alpha > -1) + ? imagecolorallocatealpha($this->getImg(), $red, $green, $blue, $alpha) + : imagecolorallocate($this->getImg(), $red, $green, $blue); + if ($textColor === FALSE) + { + throw new ImageCreationException('Could not create image text color'); + } + + // Generate placeholder text + $fontWidth = imagefontwidth($this->fontSize); + $fontHeight = imagefontheight($this->fontSize); + $length = strlen($text); + $textWidth = $length * $fontWidth; + $fxPos = (int) ceil((imagesx($this->getImg()) - $textWidth) / 2); + $fyPos = (int) ceil((imagesy($this->getImg()) - $fontHeight) / 2); + + // Add the image text + imagestring($this->getImg(), $this->fontSize, $fxPos, $fyPos, $text, $textColor); + + return $this; + } + + public function addBackgroundColor(int $red, int $green, int $blue, int $alpha=-1): self + { + $fillColor = ($alpha > -1) + ? imagecolorallocatealpha($this->getImg(), $red, $green, $blue, $alpha) + : imagecolorallocate($this->getImg(), $red, $green, $blue); + + if ($fillColor === FALSE) + { + throw new ImageCreationException('Failed to create image fill color'); + } + + $hasFilled = imagefill($this->getImg(), 0, 0, $fillColor); + if ($hasFilled === FALSE) + { + throw new ImageCreationException('Failed to add background color to image'); + } + + return $this; + } + + public function savePng(string $savePath, bool $saveAlpha = TRUE): bool + { + $setAlpha = imagesavealpha($this->getImg(), $saveAlpha); + if ($setAlpha === FALSE) + { + throw new ImageCreationException('Failed to set image save alpha flag'); + } + + return imagepng($this->getImg(), $savePath, 9); + } + + public function saveWebp(string $savePath): bool + { + return imagewebp($this->getImg(), $savePath); + } + + public function saveJpg(string $savePath): bool + { + return imagejpeg($this->getImg(), $savePath); + } + + public function saveGif(string $savePath): bool + { + return imagegif($this->getImg(), $savePath); + } + + public function cleanup(): void + { + $cleaned = FALSE; + + if ($this->getImg() instanceof GdImage) + { + $cleaned = imagedestroy($this->getImg()); + } + + if ($cleaned === FALSE) + { + throw new ImageCreationException('Failed to clean up image resource'); + } + } +}