diff --git a/src/Image.php b/src/Image.php index 6f2d477..a59715c 100644 --- a/src/Image.php +++ b/src/Image.php @@ -13,6 +13,7 @@ use SimonHamp\TheOg\Layout\Layouts\Standard; use SimonHamp\TheOg\Theme as BuiltInTheme; use SimonHamp\TheOg\Theme\BackgroundPlacement; +use SimonHamp\TheOg\Theme\Picture; class Image { @@ -22,11 +23,11 @@ class Image public readonly string $callToAction; public readonly string $description; - public readonly string $picture; + public readonly Picture $picture; public readonly string $title; public readonly string $url; - public readonly string $watermark; + public readonly Picture $watermark; public function __construct() { @@ -55,8 +56,12 @@ public function description(string $description): self /** * The picture to display */ - public function picture(string $picture): self + public function picture(string|Picture $picture): self { + if (is_string($picture)) { + $picture = new Picture($picture); + } + $this->picture = $picture; return $this; } @@ -82,8 +87,12 @@ public function url(string $url): self /** * The watermark image */ - public function watermark(string $watermark, ?float $opacity = 1.0): self + public function watermark(string|Picture $watermark): self { + if (is_string($watermark)) { + $watermark = new Picture($watermark); + } + $this->watermark = $watermark; return $this; } diff --git a/src/Interfaces/Layout.php b/src/Interfaces/Layout.php index e9db685..5781e11 100644 --- a/src/Interfaces/Layout.php +++ b/src/Interfaces/Layout.php @@ -6,6 +6,7 @@ use SimonHamp\TheOg\Border; use SimonHamp\TheOg\Image as Config; use SimonHamp\TheOg\Layout\TextBox; +use SimonHamp\TheOg\Theme\Picture; interface Layout { @@ -17,7 +18,7 @@ public function description(): ?string; public function features(): void; - public function picture(): ?string; + public function picture(): ?Picture; public function render(Config $config): Image; @@ -25,5 +26,5 @@ public function title(): string; public function url(): ?string; - public function watermark(): ?string; + public function watermark(): ?Picture; } diff --git a/src/Layout/AbstractLayout.php b/src/Layout/AbstractLayout.php index bd7d6e2..bb5307b 100644 --- a/src/Layout/AbstractLayout.php +++ b/src/Layout/AbstractLayout.php @@ -6,6 +6,7 @@ use SimonHamp\TheOg\BorderPosition; use SimonHamp\TheOg\Interfaces\Box as BoxInterface; use SimonHamp\TheOg\Interfaces\Layout; +use SimonHamp\TheOg\Theme\Picture; use SimonHamp\TheOg\Traits\RendersFeatures; abstract class AbstractLayout implements Layout @@ -56,7 +57,7 @@ public function description(): ?string return $this->config->description ?? null; } - public function picture(): ?string + public function picture(): ?Picture { return $this->config->picture ?? null; } @@ -75,7 +76,7 @@ public function url(): ?string return parse_url($this->config->url, PHP_URL_HOST) ?? $this->config->url; } - public function watermark(): ?string + public function watermark(): ?Picture { return $this->config->watermark ?? null; } diff --git a/src/Layout/Layouts/Avatar.php b/src/Layout/Layouts/Avatar.php index 3673448..7359e05 100644 --- a/src/Layout/Layouts/Avatar.php +++ b/src/Layout/Layouts/Avatar.php @@ -19,7 +19,7 @@ class Avatar extends AbstractLayout public function features(): void { $this->addFeature((new PictureBox()) - ->path($this->picture()) + ->path($this->picture()->path()) ->circle() ->box(300, 300) ->position( @@ -46,11 +46,11 @@ public function features(): void if ($watermark = $this->watermark()) { $this->addFeature((new PictureBox()) - ->path($watermark) - ->box(100, 100) + ->path($watermark->path()) + ->box(150, 150) ->position( - x: 1180, - y: 610, + x: 1150, + y: 580, anchor: Position::BottomRight ) ); diff --git a/src/Layout/Layouts/GitHubBasic.php b/src/Layout/Layouts/GitHubBasic.php index 3ef48d3..948a1ac 100644 --- a/src/Layout/Layouts/GitHubBasic.php +++ b/src/Layout/Layouts/GitHubBasic.php @@ -94,7 +94,7 @@ public function features(): void if ($watermark = $this->watermark()) { $this->addFeature((new PictureBox()) - ->path($watermark) + ->path($watermark->path()) ->box(100, 100) ->position( x: 0, diff --git a/src/Layout/Layouts/Standard.php b/src/Layout/Layouts/Standard.php index 2f092e0..1bad44d 100644 --- a/src/Layout/Layouts/Standard.php +++ b/src/Layout/Layouts/Standard.php @@ -93,7 +93,7 @@ public function features(): void if ($watermark = $this->watermark()) { $this->addFeature((new PictureBox()) - ->path($watermark) + ->path($watermark->path()) ->box(100, 100) ->position( x: 0, diff --git a/src/Layout/Layouts/TwoUp.php b/src/Layout/Layouts/TwoUp.php index 047d6b3..b071bbb 100644 --- a/src/Layout/Layouts/TwoUp.php +++ b/src/Layout/Layouts/TwoUp.php @@ -7,6 +7,7 @@ use SimonHamp\TheOg\Layout\PictureBox; use SimonHamp\TheOg\Layout\Position; use SimonHamp\TheOg\Layout\TextBox; +use SimonHamp\TheOg\Theme\PicturePlacement; class TwoUp extends AbstractLayout { @@ -20,7 +21,8 @@ public function features(): void { if ($picture = $this->picture()) { $this->addFeature((new PictureBox()) - ->path($picture) + ->path($picture->path()) + ->placement($picture->placement() ?? PicturePlacement::Cover) ->box($this->width / 2, $this->height) ->position( x: 0, @@ -70,7 +72,7 @@ public function features(): void if ($watermark = $this->watermark()) { $this->addFeature((new PictureBox()) - ->path($watermark) + ->path($watermark->path()) ->box(100, 100) ->position( x: 20, diff --git a/src/Layout/PictureBox.php b/src/Layout/PictureBox.php index b5ecd29..12228f6 100644 --- a/src/Layout/PictureBox.php +++ b/src/Layout/PictureBox.php @@ -5,18 +5,22 @@ use Imagick; use ImagickDraw; use ImagickPixel; +use Intervention\Image\Geometry\Rectangle; use Intervention\Image\ImageManager; use Intervention\Image\Interfaces\ImageInterface; +use SimonHamp\TheOg\Theme\PicturePlacement; - class PictureBox extends Box +class PictureBox extends Box { - public string $path; - /** * @var array> */ public array $maskQueue; + public string $path; + + public PicturePlacement $placement = PicturePlacement::Natural; + protected ImageInterface $picture; public function render(ImageInterface $image): void @@ -71,16 +75,33 @@ public function circle(): static return $this; } - public function path(string $path): self + public function path(string $path): static { $this->path = $path; return $this; } + public function placement(PicturePlacement $placement): static + { + $this->placement = $placement; + return $this; + } + protected function getPicture(): ImageInterface { - return $this->picture ??= ImageManager::imagick() - ->read(file_get_contents($this->path)) - ->cover($this->box->width(), $this->box->height()); + $this->picture ??= ImageManager::imagick() + ->read(file_get_contents($this->path)); + + match ($this->placement) { + PicturePlacement::Cover => $this->picture->cover($this->box->width(), $this->box->height()), + PicturePlacement::Natural => $this->picture->scaleDown(min($this->box->width(), $this->box->height())), + }; + + return $this->picture; + } + + protected function getPrerenderedBox(): Rectangle|null + { + return $this->getPicture()->size(); } } diff --git a/src/Theme/Picture.php b/src/Theme/Picture.php new file mode 100644 index 0000000..942cb72 --- /dev/null +++ b/src/Theme/Picture.php @@ -0,0 +1,59 @@ +setPath($path); + $this->setOpacity($opacity); + } + + public function opacity(): float + { + return $this->opacity; + } + + public function setOpacity(float $opacity): static + { + $this->opacity = max(0, min($opacity, 1)); + return $this; + } + + public function path(): string + { + return $this->path; + } + + public function setPath(string $path): static + { + if (filter_var($path, FILTER_VALIDATE_URL)) { + $this->isUrl = true; + } + + $this->path = $path; + return $this; + } + + public function placement(): ?PicturePlacement + { + return $this->placement ?? null; + } + + public function setPlacement(PicturePlacement $placement): static + { + $this->placement = $placement; + return $this; + } + + public function isUrl(): bool + { + return $this->isUrl; + } +} diff --git a/src/Theme/PicturePlacement.php b/src/Theme/PicturePlacement.php new file mode 100644 index 0000000..d5556d9 --- /dev/null +++ b/src/Theme/PicturePlacement.php @@ -0,0 +1,10 @@ +accentColor('#003') ->picture('https://i.pravatar.cc/300?img=10') ->title('Simone Hampstead') - ->watermark(__DIR__.'/../resources/logo.png'), + ->watermark(__DIR__.'/../resources/wide-logo.png'), 'avatar-layout', ]; } diff --git a/tests/Integration/__snapshots__/ImageTest__test_basic_image with data set avatar layout__1.png b/tests/Integration/__snapshots__/ImageTest__test_basic_image with data set avatar layout__1.png index 614bd71..d6dab18 100644 Binary files a/tests/Integration/__snapshots__/ImageTest__test_basic_image with data set avatar layout__1.png and b/tests/Integration/__snapshots__/ImageTest__test_basic_image with data set avatar layout__1.png differ diff --git a/tests/resources/wide-logo.png b/tests/resources/wide-logo.png new file mode 100644 index 0000000..8c77c3a Binary files /dev/null and b/tests/resources/wide-logo.png differ