diff --git a/README.md b/README.md index 0169795..482e1e6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # gdaisy -An image templating system based on PHP-GD to dynamically generate image banners and covers. +A highly experimental image templating system based on PHP-GD to dynamically generate image banners and covers. ## Installation @@ -16,7 +16,7 @@ composer require erikaheidi/gdaisy ### 2. Once it's installed, you can run the default script to generate an example cover based on meta tags. -Gdaisy comes with a little example script that generates a header image adequately sized for Twitter, based on a default template. The `vendor/bin/gdaisy generate` script expects the URL to fetch as first parameter and the output path as second parameter, as follows: +Gdaisy comes with an example script that generates a header image adequately sized for Twitter, based on a default template. The `vendor/bin/gdaisy generate` script expects the URL to fetch as first parameter and the output path as second parameter, as follows: ```shell ./vendor/bin/gdaisy generate https://www.digitalocean.com/community/tutorials/how-to-set-up-visual-studio-code-for-php-projects output.png @@ -28,5 +28,87 @@ This will generate the following image: gdaisy generated cover image

-The example generation script is defined in `vendor/erikaheidi/gdaisy/bin/gdaisy`, and the default template is defined in `vendor/erikaheidi/gdaisy/resources/templates/article_preview.json`. You can use those as base to build your own image templates, using differet content sources. +The example generation script is defined in `vendor/erikaheidi/gdaisy/bin/gdaisy`. + +## Creating Templates + +Consider the following `basic.json` template example: + +```json +{ + "width": 600, + "height": 600, + "background": "FFFFFF", + "elements": { + "title": { + "type": "text", + "properties": { + "pos_x": 50, + "pos_y": 20, + "size": 30, + "color": "666666", + "max_width": 500, + "align": "center" + } + }, + "thumbnail": { + "type": "image", + "properties": { + "pos_x": 50, + "pos_y": 50, + "width": 500, + "height": 500 + } + } + } +} +``` + +This template has two elements: `title` (type `text`) and `thumbnail` (type `image`). + +**Template Properties:** + +- `width`: Resulting image width +- `height`: Resulting image height +- `background`: Resulting image background + +**Text Properties:** + +- `pos_x`: X coordinate (bottom left X coordinate for the base of text) +- `pos_y`: Y coordinate (botom left Y coordinate for the base of text) +- `size`: Text size +- `color`: Text Color (hex) +- `max_width` (optional): Maximum text width - text will be broken down into multiple lines when set +- `align` (optional): Text align, possible values are `left`(default), `center`, or `right`. +- `font`: path to font file (ttf) + +**Image Properties:** + +- `pos_x`: X coordinate (top left corner) where the image will be applied +- `pos_y`: Y coordinate (top left corner) where the image will be applied, +- `width`: width (will proportially resize to fit) +- `height`: height (will proportially resize to fit) +- `image_file` (optional): when set, will use this image, otherwise you'll have to provide this as parameter when applying the template +- `crop` (optional): when set to `center`, will resize-crop while centering the image. Default is `left`, can also be set to `right`. + +Following, a PHP script to generate a new image based on the example template: + +```php +apply("thumbnail", [ + "image_file" => __DIR__ . '/resources/images/gdaisy.png' +])->apply("title", [ + "text" => "generated with gdaisy" +]); + +$template->write('output.png'); +echo "Finished.\n"; +``` diff --git a/bin/gdaisy b/bin/gdaisy index 2703815..92744b2 100755 --- a/bin/gdaisy +++ b/bin/gdaisy @@ -66,13 +66,15 @@ $gdaisy->registerCommand('generate', function() use ($gdaisy, $input) { $title = $tags['twitter:title'] ?? get_page_title($url) ?? 'Gdaisy'; $description = $tags['twitter:description'] ?? $tags['description'] ?? 'Generated with erikaheidi/gdaisy'; - $elements = [ - 'title' => [ "text" => html_entity_decode($title, ENT_QUOTES) ], - 'description' => [ "text" => html_entity_decode($description . '...', ENT_QUOTES) ], - 'thumbnail' => [ "image_file" => $image_file] - ]; - $template->build($elements); + $template->apply("title", [ + "text" => html_entity_decode($title, ENT_QUOTES) + ])->apply("description", [ + "text" => html_entity_decode($description . '...', ENT_QUOTES) + ])->apply("thumbnail", [ + "image_file" => $image_file + ]); + $template->write($dest); $gdaisy->getPrinter()->info("Image saved to $dest."); diff --git a/src/ImagePlaceholder.php b/src/ImagePlaceholder.php index f16263f..8418713 100644 --- a/src/ImagePlaceholder.php +++ b/src/ImagePlaceholder.php @@ -52,6 +52,11 @@ public function apply($resource, array $params = []) $copy_x = ($original_w / 2) - ($this->width / 2); $copy_y = ($original_h / 2) - ($this->height / 2); } + + if ($this->crop === "right") { + $copy_x = $this->width - $original_w; + $copy_y = $this->height - $original_h; + } } imagecopyresized( diff --git a/src/Template.php b/src/Template.php index 28b7b1a..a226092 100644 --- a/src/Template.php +++ b/src/Template.php @@ -71,7 +71,7 @@ public function write(string $path) imagepng($this->getResource(), $path); } - public function apply(string $key, array $params = []) + public function apply(string $key, array $params = []): Template { /** @var PlaceholderInterface $placeholder */ $placeholder = $this->getPlaceholder($key); @@ -79,6 +79,8 @@ public function apply(string $key, array $params = []) if ($placeholder) { $placeholder->apply($this->getResource(), $params); } + + return $this; } public function getResource() diff --git a/src/TextPlaceholder.php b/src/TextPlaceholder.php index 19aa608..184d7ce 100644 --- a/src/TextPlaceholder.php +++ b/src/TextPlaceholder.php @@ -14,6 +14,8 @@ class TextPlaceholder implements PlaceholderInterface public ?int $max_width; + public string $align; + public int $size; static int $spacing = 2; @@ -27,6 +29,7 @@ public function __construct(array $params = []) $this->font = __DIR__ . '/../' . $font; $this->color = $params['color'] ?? "000000"; $this->max_width = $params['max_width'] ?? null; + $this->align = $params['align'] ?? 'left'; } public function apply($resource, array $params = []) @@ -37,18 +40,34 @@ public function apply($resource, array $params = []) $width = $size[2] - $size[0]; $height = ($size[7] - $size[1]) * -1; - if ($this->max_width) { - if ($width > $this->max_width) { - $max_letters = (strlen($params['text']) * $this->max_width) / $width; - $wrapped = wordwrap($params['text'], $max_letters, "#"); - $lines = explode("#", $wrapped); - } + if (!$this->max_width) { + $this->max_width = imagesx($resource); + } + + if ($width > $this->max_width) { + $max_letters = (strlen($params['text']) * $this->max_width) / $width; + $wrapped = wordwrap($params['text'], $max_letters, "#"); + $lines = explode("#", $wrapped); } $count = 1; foreach ($lines as $text) { $pos_y = $this->pos_y + ($count * $height) + self::$spacing; - imagettftext($resource, $this->size, 0, $this->pos_x, $pos_y, $color, $this->font, $text); + $pos_x = $this->pos_x; + + if ($this->align != "left") { + $size = imagettfbbox($this->size, 0, $this->font, $params['text']); + + if ($this->align === "center") { + $pos_x = (($this->pos_x + $this->max_width) / 2) - (($size[2] - $size[0]) / 2); + } + + if ($this->align === "right") { + $pos_x = ($this->pos_x + $this->max_width) - ($size[2] - $size[0]); + } + } + + imagettftext($resource, $this->size, 0, $pos_x, $pos_y, $color, $this->font, $text); $count++; } }