Skip to content

Commit

Permalink
Merge pull request #22 from simonhamp/avatar-layout
Browse files Browse the repository at this point in the history
Avatar layout
  • Loading branch information
simonhamp committed Jan 15, 2024
2 parents e6c14f2 + 6ce11c6 commit 9f9bffb
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 20 deletions.
3 changes: 3 additions & 0 deletions src/Interfaces/Box.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

namespace SimonHamp\TheOg\Interfaces;

use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\ImageInterface;

interface Box
{
public function anchor(): Point;

public function name(string $name): static;

public function getName(): ?string;
Expand Down
21 changes: 9 additions & 12 deletions src/Layout/Box.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,32 @@

namespace SimonHamp\TheOg\Layout;

use Closure;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Interfaces\ImageInterface;
use SimonHamp\TheOg\Interfaces\Box as BoxInterface;

readonly class Box implements BoxInterface
class Box implements BoxInterface
{
public Position $anchor;

public Rectangle $box;

public string $name;
public readonly string $name;

public Point $position;
public readonly Rectangle $renderedBox;

public readonly Point $position;

/**
* @var Closure<Box>
*/
public mixed $relativeTo;

public Position $relativeToPosition;

public Rectangle $renderedBox;
public readonly Closure $relativeTo;

public function box(int $width, int $height): self
public function box(int|float $width, int|float $height): self
{
$this->box = new Rectangle($width, $height);
$this->box = new Rectangle(intval(floor($width)), intval(floor($height)));
return $this;
}

Expand All @@ -39,15 +38,13 @@ public function position(
int $x,
int $y,
?callable $relativeTo = null,
Position $position = Position::TopLeft,
Position $anchor = Position::TopLeft
): self
{
$this->position = new Point($x, $y);

if ($relativeTo) {
$this->relativeTo = $relativeTo;
$this->relativeToPosition = $position;
}

$this->anchor = $anchor;
Expand Down
52 changes: 52 additions & 0 deletions src/Layout/Layouts/Avatar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace SimonHamp\TheOg\Layout\Layouts;

use SimonHamp\TheOg\BorderPosition;
use SimonHamp\TheOg\Layout\AbstractLayout;
use SimonHamp\TheOg\Layout\PictureBox;
use SimonHamp\TheOg\Layout\Position;
use SimonHamp\TheOg\Layout\TextBox;

class Avatar extends AbstractLayout
{
protected BorderPosition $borderPosition = BorderPosition::Left;
protected int $borderWidth = 25;
protected int $height = 630;
protected int $padding = 40;
protected int $width = 1200;

public function features(): void
{
$this->addFeature((new PictureBox())
->path($this->picture())
->circle()
->box(300, 300)
->position(
x: 0,
y: 0,
relativeTo: fn () => $this->mountArea()->anchor(Position::Center)->moveY(-100),
anchor: Position::Center,
)
);

$this->addFeature((new TextBox())
->text($this->title())
->color($this->config->theme->getTitleColor())
->font($this->config->theme->getTitleFont())
->size(56)
->box($this->mountArea()->box->width() / 1.5, 300)
->position(
x: 0,
y: 0,
relativeTo: fn () => $this->mountArea()->anchor(Position::Center)->moveY(100),
anchor: Position::MiddleTop,
)
);
}

public function url(): string
{
return strtoupper(parent::url());
}
}
74 changes: 67 additions & 7 deletions src/Layout/PictureBox.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,87 @@

namespace SimonHamp\TheOg\Layout;

use Intervention\Image\Drivers\Imagick\Modifiers\PlaceModifier;
use Intervention\Image\Image;
use Imagick;
use ImagickDraw;
use ImagickPixel;
use Intervention\Image\ImageManager;
use Intervention\Image\Interfaces\ImageInterface;

readonly class PictureBox extends Box
class PictureBox extends Box
{
public string $path;

/**
* @var array<callable<Imagick>>
*/
public array $maskQueue;

protected ImageInterface $picture;

public function render(ImageInterface $image): void
{
$picture = ImageManager::imagick()
->read(file_get_contents($this->path))
->cover($this->box->width(), $this->box->height());
if (! empty($this->maskQueue)) {
foreach ($this->maskQueue as $mask) {
$this->mask($mask());
}
}

$position = $this->calculatePosition();

$image->place(
element: $this->getPicture(),
offset_x: $position->x(),
offset_y: $position->y()
);
}

/**
* Apply a mask image to the picture
*/
public function mask(Imagick $mask): void
{
$base = $this->getPicture()->core()->native();

$base->setImageMatte(true);

$base->compositeImage($mask, Imagick::COMPOSITE_DSTIN, 0, 0);

$base->writeImage(__DIR__.'/../../circle.png');
}

public function circle(): static
{
$this->maskQueue[] = function () {
$width = $this->box->width();
$start = intval(floor($width / 2));

// Create the circle
$circle = new ImagickDraw();
$circle->setFillColor(new ImagickPixel('#fff'));
$circle->circle($start, $start, $start, $width - 10);

// Draw it to an Imagick instance
$image = new Imagick();
$image->newImage($width, $width, 'none', 'png');
$image->setImageMatte(true);
$image->drawImage($circle);

return $image;
};

$image->place($picture);
return $this;
}

public function path(string $path): self
{
$this->path = $path;
return $this;
}

protected function getPicture(): ImageInterface
{
return $this->picture ??= ImageManager::imagick()
->read(file_get_contents($this->path))
->cover($this->box->width(), $this->box->height());
}
}
2 changes: 1 addition & 1 deletion src/Layout/TextBox.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use SimonHamp\TheOg\Interfaces\Font;
use SimonHamp\TheOg\Modifiers\TextModifier as CustomTextModifier;

readonly class TextBox extends Box
class TextBox extends Box
{
public ColorInterface $color;
public Font $font;
Expand Down
10 changes: 10 additions & 0 deletions tests/Integration/ImageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use SimonHamp\TheOg\Background as BuiltInBackground;
use SimonHamp\TheOg\BorderPosition;
use SimonHamp\TheOg\Image;
use SimonHamp\TheOg\Layout\Layouts\Avatar;
use SimonHamp\TheOg\Layout\Layouts\GitHubBasic;
use SimonHamp\TheOg\Layout\Layouts\TwoUp;
use SimonHamp\TheOg\Theme;
Expand Down Expand Up @@ -170,5 +171,14 @@ public static function snapshotImages(): iterable
->callToAction('ONLY $99!'),
'twoup-custom-theme',
];

yield 'avatar layout' => [
(new Image())
->layout(new Avatar)
->accentColor('#003')
->picture('https://i.pravatar.cc/300?img=10')
->title('Simone Hampstead'),
'avatar-layout',
];
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 9f9bffb

Please sign in to comment.