Skip to content

Commit

Permalink
preview generator
Browse files Browse the repository at this point in the history
  • Loading branch information
RobinDev committed May 8, 2023
1 parent 07717e5 commit 6374511
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 4 deletions.
1 change: 1 addition & 0 deletions composer.json
Expand Up @@ -23,6 +23,7 @@
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^2.8.1",
"fortawesome/font-awesome": "^6.1",
"imagine/imagine": "^1.3",
"intervention/image": "^2.5",
"michelf/php-markdown": "^2",
"miljar/php-exif": "^0.6.5",
Expand Down
1 change: 1 addition & 0 deletions packages/core/composer.json
Expand Up @@ -17,6 +17,7 @@
"intervention/image": "^2.5",
"michelf/php-markdown": "^2",
"pagerfanta/twig": "^4.1",
"imagine/imagine": "^1.3",
"piedweb/render-html-attributes": "^2.0.1",
"piedweb/curl": "^0.1",
"piedweb/extractor": "^0.1.19",
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/Component/App/AppConfig.php
Expand Up @@ -103,6 +103,17 @@ public function has(string $key): bool
return null !== $this->get($key);
}

public function getStr(string $key, string $default = ''): string
{
$returnValue = $this->get($key) ?? $default;

if (! \is_string($returnValue) && ! \is_int($returnValue) && ! \is_float($returnValue)) {
throw new \LogicException('`'.$key.'` is not stringable');
}

return (string) $returnValue;
}

/** @return mixed */
public function get(string $key)
{
Expand Down
13 changes: 10 additions & 3 deletions packages/core/src/EventListener/PageListener.php
Expand Up @@ -3,12 +3,17 @@
namespace Pushword\Core\EventListener;

use Pushword\Core\Entity\PageInterface;
use Symfony\Component\Security\Core\Security;
use Pushword\Core\Service\PageOpenGraphImageGenerator;
use Symfony\Bundle\SecurityBundle\Security;

// Symfony\Component\Security\Core\Security;

final class PageListener
{
public function __construct(private readonly Security $security)
{
public function __construct(
private readonly Security $security,
private readonly PageOpenGraphImageGenerator $pageOpenGraphImageGenerator,
) {
}

public function preRemove(PageInterface $page): void
Expand All @@ -25,11 +30,13 @@ public function prePersist(PageInterface $page): void
{
$this->setIdAsSlugIfNotDefined($page);
$this->updatePageEditor($page);
$this->pageOpenGraphImageGenerator->setPage($page)->generatePreviewImage();
}

public function preUpdate(PageInterface $page): void
{
$this->updatePageEditor($page);
$this->pageOpenGraphImageGenerator->setPage($page)->generatePreviewImage();
}

/**
Expand Down
150 changes: 150 additions & 0 deletions packages/core/src/Service/PageOpenGraphImageGenerator.php
@@ -0,0 +1,150 @@
<?php

namespace Pushword\Core\Service;

use Imagine\Draw\DrawerInterface;
use Imagine\Gd\Font;
use Imagine\Image\Box;
use Imagine\Image\ImageInterface;
use Imagine\Image\ImagineInterface;
use Imagine\Image\Palette\Color\ColorInterface;
use Imagine\Image\Palette\RGB;
use Imagine\Image\Point;
use Pushword\Core\Component\App\AppPool;
use Pushword\Core\Entity\PageInterface;
use Symfony\Component\Filesystem\Filesystem;
use Twig\Environment as Twig;

/**
* Credit JoliCode
* https://jolicode.com/blog/create-your-own-shiny-open-graph-images-with-imagine-php.
*/
class PageOpenGraphImageGenerator
{
private ?RGB $rgb = null;

private ?ImagineInterface $imagine = null;

public PageInterface $page;

public function __construct(
private readonly AppPool $apps,
private readonly Twig $twig,
private readonly Filesystem $filesystem,
private readonly string $publicDir,
private readonly string $publicMediaDir,
private readonly int $imageHeight = 600,
private readonly int $imageWidth = 1200,
private readonly int $marginSize = 40,
) {
if (null !== $this->apps->getCurrentPage()) {
$this->page = $this->apps->getCurrentPage();
}
}

public function getPath(bool $browserPath = false): string
{
return ($browserPath ? '' : $this->publicDir).'/'.$this->publicMediaDir.'/og/'
.str_replace('/', '_', $this->page->getSlug()).'.png';
}

public function generatePreviewImage(): void
{
$image = $this->getImagine()->create(
new Box($this->imageWidth, $this->imageHeight),
);

$drawer = $image->draw();
$this->drawTitle($drawer);
$this->drawAuthorName($drawer);
$this->drawLogo($image);
$this->drawFooter($drawer);

$this->filesystem->mkdir($this->publicDir.'/'.$this->publicMediaDir.'/og/');

$image->save($this->getPath());
}

private function drawTitle(DrawerInterface $drawer): void
{
$titleText = $this->page->getH1() ?? '...';

if (\strlen($titleText) > 90) {
$titleText = substr($titleText, 0, 87).'…';
}

$drawer->text(
$titleText,
$this->getFont('regular', 40),
new Point($this->marginSize, 150),
0,
$this->imageWidth - $this->marginSize * 2
);
}

private function drawAuthorName(DrawerInterface $drawer): void
{
$author = $this->apps->get()->getHosts()[0];
// $this->page->getCustomProperty('Author') ?? ' ';

$drawer->text(
$author,
$this->getFont('light', 30),
new Point($this->marginSize, 100),
);
}

private function drawFooter(DrawerInterface $drawer): void
{
$leftTop = new Point(0, $this->imageHeight - 10);
$rightBottom = new Point($this->imageWidth, $this->imageHeight);

$drawer->rectangle(
$leftTop,
$rightBottom,
$this->getRgb()->color($this->apps->get()->getStr('css_var:color_primary', '#EF8206')), // replace per primary
true,
);
}

private function drawLogo(ImageInterface $image): void
{
$logo = $this->getImagine()->open($this->twig->getLoader()->getSourceContext('@Pushword/page/OpenGrapImageGenerator/logo.png')->getPath());
$logoSize = $logo->getSize();
$bottomRight = new \Imagine\Image\Point(
$this->imageWidth - $logoSize->getWidth() - $this->marginSize,
$this->imageHeight - $logoSize->getHeight() - $this->marginSize
);
$image->paste($logo, $bottomRight);
}

private function getFont(string $fontType = 'bold', int $size = 37, ?ColorInterface $color = null): Font
{
return new Font(
$this->twig->getLoader()->getSourceContext('@Pushword/page/OpenGrapImageGenerator/'.$fontType.'.ttf')->getPath(),
$size,
$color ?? $this->getRgb()->color('#0f172a')
);
}

private function getImagine(): ImagineInterface
{
return $this->imagine ?? new \Imagine\Imagick\Imagine();
}

private function getRgb(): RGB
{
if (null === $this->rgb) {
return $this->rgb = new RGB();
}

return $this->rgb;
}

public function setPage(PageInterface $page): static
{
$this->page = $page;

return $this;
}
}
16 changes: 15 additions & 1 deletion packages/core/src/Twig/AppExtension.php
Expand Up @@ -15,6 +15,7 @@
use Pushword\Core\Repository\Repository;
use Pushword\Core\Router\RouterInterface;
use Pushword\Core\Service\ImageManager;
use Pushword\Core\Service\PageOpenGraphImageGenerator;
use Pushword\Core\Utils\FilesizeFormatter;
use Pushword\Core\Utils\HtmlBeautifer;
use Pushword\Core\Utils\MarkdownParser;
Expand Down Expand Up @@ -48,7 +49,8 @@ public function __construct(
private AppPool $apps,
private Twig $twig,
private ImageManager $imageManager,
private ManagerPoolInterface $entityFilterManagerPool
private ManagerPoolInterface $entityFilterManagerPool,
private PageOpenGraphImageGenerator $pageOpenGraphImageGenerator,
) {
}

Expand Down Expand Up @@ -106,9 +108,21 @@ public function getFunctions(): array
new TwigFunction('contains_link_to', [$this, 'containsLinkTo'], self::options()),
new TwigFunction('image_dimensions', [$this->imageManager, 'getDimensions'], self::options()),
new TwigFunction('class_exists', 'class_exists'),
new TwigFunction('open_graph_image_generated_path', [$this, 'getOpenGraphImageGeneratedPath']),
];
}

public function getOpenGraphImageGeneratedPath(PageInterface $page): ?string
{
$this->pageOpenGraphImageGenerator->page = $page;

if (! file_exists($this->pageOpenGraphImageGenerator->getPath())) {
return null;
}

return $this->pageOpenGraphImageGenerator->getPath(true);
}

public function getPagePosition(PageInterface $page): int
{
if (null !== $page->getParentPage()) {
Expand Down
Binary file not shown.
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
5 changes: 5 additions & 0 deletions packages/core/src/templates/page/page_default.html.twig
Expand Up @@ -45,6 +45,11 @@
{% endif %}
{% if page.mainImage is defined and page.mainImage is not null %}
<meta name="og:image" content="{{ apps.get().baseUrl|default('') }}{{ (page.mainImage)|image('default') }}">
{% else %}
{% set generated_image = open_graph_image_generated_path(page) %}
{% if generated_image is not null %}
<meta name="og:image" content="{{ open_graph_image_generated_path(page) }}">
{% endif %}
{% endif %}
<script>const base = "{{ page('homepage') }}"</script>
{% endblock %}
Expand Down
Binary file modified packages/skeleton/var/app.db
Binary file not shown.

0 comments on commit 6374511

Please sign in to comment.