Last active
May 3, 2023 11:50
-
-
Save HedicGuibert/3ff3c99c90329448a7f7dd5b18a433b9 to your computer and use it in GitHub Desktop.
The ArticlePreviewRenderer class showcased in an article describing how to use Imagine to create article preview images
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App; | |
use Imagine\Gd\Font; | |
use Imagine\Image\Box; | |
use Imagine\Image\Point; | |
use Imagine\Image\Palette\RGB; | |
use Imagine\Image\Point\Center; | |
use Imagine\Draw\DrawerInterface; | |
use Imagine\Image\ImageInterface; | |
use Imagine\Image\ImagineInterface; | |
use Imagine\Image\Fill\Gradient\Vertical; | |
class ArticlePreviewRenderer | |
{ | |
public function __construct( | |
private readonly ImagineInterface $imagine, | |
private readonly string $publicDir, | |
private readonly RGB $rgb = new RGB(), | |
private readonly int $imageHeight = 600, | |
private readonly int $imageWidth = 1200, | |
private readonly int $marginSize = 35, | |
private ?Font $footerFont = null, | |
) { | |
$this->footerFont = new Font( | |
$this->publicDir . '/font/alatsi/Alatsi-Regular.ttf', | |
22, | |
$this->rgb->color('#FFF') | |
); | |
} | |
public function generatePreviewImage(): void | |
{ | |
$image = $this->imagine->create( | |
new Box($this->imageWidth, $this->imageHeight), | |
); | |
$drawer = $image->draw(); | |
$this->drawBackgroundImage($image); | |
$this->drawTitle($drawer); | |
$this->drawLogo($drawer); | |
$this->drawFooter($drawer); | |
$image->save($this->publicDir . '/img/shinyPreviewImage.png'); | |
} | |
private function drawFooter(DrawerInterface $drawer): void | |
{ | |
$leftTop = new Point(0, $this->imageHeight - 100); | |
$rightBottom = new Point($this->imageWidth, $this->imageHeight); | |
$drawer->rectangle( | |
$leftTop, | |
$rightBottom, | |
$this->rgb->color('#9900FF'), | |
true, | |
); | |
$this->drawAuthorName($drawer); | |
$this->drawDate($drawer); | |
} | |
private function drawTitle(DrawerInterface $drawer): void | |
{ | |
$titleText = 'Create your own shiny preview images with Imagine PHP'; | |
$titleFont = new Font( | |
$this->publicDir . '/font/Butler/Butler_Medium.otf', | |
32, | |
$this->rgb->color('#2b2b2a') | |
); | |
if (\strlen($titleText) > 90) { | |
$titleText = substr($titleText, 0, 87) . '...'; | |
} | |
$drawer->text( | |
$titleText, | |
$titleFont, | |
new Point($this->marginSize, $this->marginSize), | |
0, | |
$this->imageWidth / 1.5 | |
); | |
} | |
private function drawLogo(DrawerInterface $drawer): void | |
{ | |
$squareSideWidth = 100; | |
$squareLeftStart = $this->imageWidth - $this->marginSize - $squareSideWidth; | |
$squareBottomEnd = $this->marginSize + $squareSideWidth; | |
$leftTop = new Point($squareLeftStart, $this->marginSize); | |
$rightBottom = new Point($this->imageWidth - $this->marginSize, $squareBottomEnd); | |
$drawer->rectangle( | |
$leftTop, | |
$rightBottom, | |
$this->rgb->color('#9900FF'), | |
true, | |
); | |
$logoFont = new Font( | |
$this->publicDir . '/font/alatsi/Alatsi-Regular.ttf', | |
22, | |
$this->rgb->color('#9900FF') | |
); | |
$drawer->text( | |
'SQUARE', | |
$logoFont, | |
new Point($squareLeftStart - 30, $this->marginSize - 23), | |
90 | |
); | |
$drawer->text( | |
'CORP', | |
$logoFont, | |
new Point($squareLeftStart + 16, $this->marginSize + $squareSideWidth + 5), | |
); | |
} | |
private function drawAuthorName(DrawerInterface $drawer): void | |
{ | |
$drawer->text( | |
'HÉDIC GUIBERT', | |
$this->footerFont, | |
new Point($this->marginSize, $this->imageHeight - 60) | |
); | |
} | |
private function drawDate(DrawerInterface $drawer): void | |
{ | |
$date = new \DateTime(); | |
$drawer->text( | |
date('j F Y', strtotime($date->format('m/d/Y'))), | |
$this->footerFont, | |
new Point($this->imageWidth - 200, $this->imageHeight - 60) | |
); | |
} | |
private function drawBackgroundImage(ImageInterface $image): void | |
{ | |
$backgroundImage = $this->imagine->open($this->publicDir . '/img/nicolas_cage.jpg'); | |
$aspectRatio = $backgroundImage->getSize()->getHeight() / $backgroundImage->getSize()->getWidth(); | |
$resizedHeight = $aspectRatio * $this->imageWidth; | |
if ($resizedHeight >= $this->imageHeight) { | |
// The image has sufficient height. We need to resize it horizontally and to center it vertically. | |
$backgroundImage->resize($backgroundImage->getSize()->widen($this->imageWidth)); | |
$center = new Center(new Box($this->imageWidth, $backgroundImage->getSize()->getHeight() / 2)); | |
// Some images don't crop well because their height, once resized, is too short. These will render with some white space at the bottom. | |
// To prevent this, we don't center them vertically. It will not really be noticeable since their new height will be very close to the box height. | |
if ($center->getY() >= 200) { | |
$backgroundImage->crop( | |
new Point(0, $center->getY()), | |
$image->getSize() | |
); | |
} | |
} else { | |
// The image has insufficient height. We need to resize it vertically and to center it horizontally. | |
$backgroundImage->resize($backgroundImage->getSize()->heighten($this->imageHeight)); | |
$center = new Center(new Box($backgroundImage->getSize()->getWidth() / 2, $backgroundImage->getSize()->getHeight())); | |
// Some images don't crop well because their width, once resized, is too narrow. These will render with some white space on the right. | |
// To prevent this, we don't center them horizontally. It will not really be noticeable since their new width will be very close to the box width. | |
if ($center->getX() >= 390) { | |
$backgroundImage->crop( | |
new Point($center->getX(), 0), | |
$image->getSize() | |
); | |
} | |
} | |
$white = $backgroundImage->palette()->color('fff'); | |
$fill = new Vertical( | |
$backgroundImage->getSize()->getHeight(), | |
$white->dissolve(-30), | |
$white->dissolve(-30), | |
); | |
$transparentImage = $this->imagine->create($backgroundImage->getSize()) | |
->fill($fill); | |
$backgroundImage->paste($transparentImage, new Point(0, 0)); | |
$image->paste($backgroundImage, new Point(0, 0)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment