void/og-image

A minimal Open Graph Image generator library

Maintainers

Package info

github.com/raphalogou/og-image

pkg:composer/void/og-image

Statistics

Installs: 12

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-03-26 13:17 UTC

This package is auto-updated.

Last update: 2026-03-26 13:19:43 UTC


README

A standalone PHP library for generating dynamic Open Graph (OG) images, with optional Symfony bundle integration.

Overview

OG Image provides a flexible, extensible system to programmatically generate custom Open Graph images. Perfect for creating dynamic social media preview images with titles, descriptions, badges, and custom themes.

Works standalone or as a Symfony bundle - use it however you prefer!

Features

  • 🎨 Customizable Themes - Define colors, backgrounds, and fonts
  • 📐 Flexible Layout System - Built-in layouts and easy to extend
  • 🏷️ Badge Support - Add category/status badges to your images
  • 🔄 Multiple Formats - Render to WebP (default) or PNG
  • 🚀 Simple API - Intuitive, functional approach with immediate rendering
  • 🔌 Zero Dependencies - Core library has no external dependencies (except Intervention Image)
  • 🎯 Standalone & Bundle - Use as a library or register as a Symfony bundle

Requirements

  • PHP 8.2+
  • Intervention Image 3.11+
  • Image Driver: One of:
    • GD (bundled with PHP, recommended)
    • Imagick (optional, for better performance)

Optional (for Symfony integration):

  • Symfony 7.4 or 8.0+

At least one image driver must be available. GD is included with most PHP installations by default.

Installation

Via Composer

composer require void/og-image

Quick Start - Standalone

use Intervention\Image\ImageManager;
use Void\OgImage\Generator;
use Void\OgImage\Model\ImageContent;
use Void\OgImage\Layout\StandardLayout;
use Void\OgImage\Enum\Format;

// Initialize image manager with your driver
$imageManager = ImageManager::gd();  // or ImageManager::imagick()

// Create content
$content = new ImageContent(
    title: 'My Article Title',
    description: 'A brief description of the article'
);

// Generate image (uses default theme if not provided)
$generator = new Generator($imageManager);
$result = $generator->generate(
    data: $content,
    layout: new StandardLayout(),
    theme: null,  // optional - uses layout's default theme
    format: Format::Webp  // or Format::Png
);

// Use the result
$binary = $result->toString();        // Binary image data
$dataUri = $result->toBase64();       // Data URI for HTML
$stream = $result->toStream();        // Stream resource
$mimeType = $result->mimeType();      // 'image/webp' or 'image/png'
$width = $result->getWidth();         // Image width
$height = $result->getHeight();       // Image height

Quick Start - Symfony Bundle

Register the Bundle

// config/bundles.php
return [
    // ...
    Void\OgImage\Symfony\OgImageBundle::class => ['all' => true],
];

Use in Your Application

use Void\OgImage\Generator;
use Void\OgImage\Model\ImageContent;
use Void\OgImage\Layout\StandardLayout;
use Void\OgImage\Enum\Format;

class ArticleService
{
    public function __construct(private Generator $generator) {}

    public function generateOgImage(string $title, string $description): string
    {
        $content = new ImageContent(
            title: $title,
            description: $description
        );

        $result = $this->generator->generate(
            data: $content,
            layout: new StandardLayout(),
            format: Format::Webp
        );

        // Save to filesystem or return binary
        return $result->toString();
    }
}

Core Concepts

ImageContent

The data model for your OG image:

use Void\OgImage\Model\ImageContent;
use Void\OgImage\Model\Badge;

$content = new ImageContent(
    title: 'Article Title',                    // Required
    description: 'Article description',        // Optional
    badges: [                                  // Optional array of Badge objects
        new Badge('category', 'Technology'),
        new Badge('status', 'Published'),
    ],
    extras: []                                 // Optional - additional data for custom layouts
);

Theme

Customize the appearance of your images:

use Void\OgImage\Theme;
use Void\OgImage\Model\Background;
use Void\OgImage\Model\Font;

$theme = new Theme(
    primaryColor: '#6366f1',                          // Optional accent color
    background: new Background(
        color: '#0f172a',                             // Background color
        image: null,                                  // Optional background image path
        fit: Fit::Cover,                              // How to fit the image
        spacing: 20,                                  // Spacing for Repeat fit
        opacity: 0.8                                  // Opacity for image background
    ),
    textColor: '#ffffff',                             // Optional text color
    mutedColor: '#999999',                            // Optional muted/secondary text color
    titleFont: new Font(
        path: '/path/to/font.ttf',                    // Font file path
        size: 64,                                     // Font size in pixels
        color: '#000000'                              // Font color
    ),
    bodyFont: new Font(                               // For description text
        path: '/path/to/font.ttf',
        size: 32,
        color: '#333333'
    ),
    badgeFont: new Font(                              // For badge text
        path: '/path/to/font.ttf',
        size: 16,
        color: '#ffffff'
    ),
    padding: 40,                                      // Content padding
    logo: '/path/to/logo.png',                        // Optional logo/watermark
    logoScale: 0.5,                                   // Logo scale factor
    badges: null                                      // Optional default badge styles
);

Background

Control how backgrounds are rendered:

use Void\OgImage\Model\Background;
use Void\OgImage\Enum\Fit;

$background = new Background(
    color: '#ffffff',                    // Fallback/primary color
    image: '/path/to/image.png',        // Optional background image
    fit: Fit::Cover,                    // Fit mode: Cover, Contain, Center, Repeat, Stretch
    spacing: 10,                        // Spacing for Repeat mode
    opacity: 1.0                        // Opacity (0-1) for image
);

Layouts

Built-in layouts for common patterns:

StandardLayout

The default layout with title, description, and badges:

use Void\OgImage\Layout\StandardLayout;

$layout = new StandardLayout();
$result = $generator->generate($content, $layout);

Image Formats

Generate WebP or PNG images:

use Void\OgImage\Enum\Format;

// WebP (default, smaller file size, better compression)
$result = $generator->generate($content, $layout, $theme, Format::Webp);

// PNG (broader compatibility, larger file size)
$result = $generator->generate($content, $layout, $theme, Format::Png);

Extending

Custom Layouts

Create your own layout by extending AbstractLayout:

use Intervention\Image\Interfaces\ImageManagerInterface;
use Void\OgImage\Canvas;
use Void\OgImage\Layout\AbstractLayout;
use Void\OgImage\Model\ImageContent;
use Void\OgImage\Theme;

class CustomLayout extends AbstractLayout
{
    public function defaultTheme(): Theme
    {
        return new Theme(
            primaryColor: '#ff0000',
            // ... other default theme properties
        );
    }

    public function build(
        ImageManagerInterface $imageManager,
        ImageContent $data,
        ?Theme $theme = null
    ): Canvas {
        $canvas = new Canvas(1200, 630, $imageManager);

        // Set background
        $canvas->setBackground($theme->background ?? new Background(color: '#ffffff'));

        // Add your custom rendering logic here
        // Use $canvas->add($box, $position) to add elements

        return $canvas;
    }
}

Custom Fonts

Use different fonts for various text elements:

use Void\OgImage\Model\Font;

$theme = new Theme(
    titleFont: new Font('/path/to/bold-font.ttf', 64, '#000000'),
    bodyFont: new Font('/path/to/regular-font.ttf', 32, '#333333'),
    badgeFont: new Font('/path/to/small-font.ttf', 16, '#ffffff')
);

Custom Badges

Add badges to your content:

use Void\OgImage\Model\Badge;
use Void\OgImage\Model\ImageContent;

$content = new ImageContent(
    title: 'Article Title',
    description: 'Description',
    badges: [
        new Badge('Technology', 'Python'),
        new Badge('Status', 'Published'),
        new Badge('Category', 'Tutorial'),
    ]
);

Enums

The library includes helpful enums for configuration:

Format - Image output format:

use Void\OgImage\Enum\Format;

Format::Webp  // Default
Format::Png

Fit - Background image fitting:

use Void\OgImage\Enum\Fit;

Fit::Cover      // Crop to fill
Fit::Contain    // Scale to fit
Fit::Center     // Center without scaling
Fit::Repeat     // Tile the image
Fit::Stretch    // Stretch to fill

TextAlignment - Text alignment within boxes:

use Void\OgImage\Enum\TextAlignment;

TextAlignment::Left
TextAlignment::Center
TextAlignment::Right

Overflow - Text overflow handling:

use Void\OgImage\Enum\Overflow;

Overflow::Visible
Overflow::Hidden
Overflow::Ellipsis

Placement - Element positioning:

use Void\OgImage\Enum\Placement;

Placement::TopLeft
Placement::Top
Placement::TopRight
Placement::Left
Placement::Center
Placement::Right
Placement::BottomLeft
Placement::Bottom
Placement::BottomRight

Complete Example

use Intervention\Image\ImageManager;
use Void\OgImage\Generator;
use Void\OgImage\Model\ImageContent;
use Void\OgImage\Model\Badge;
use Void\OgImage\Model\Font;
use Void\OgImage\Model\Background;
use Void\OgImage\Layout\StandardLayout;
use Void\OgImage\Theme;
use Void\OgImage\Enum\Format;

// Setup
$imageManager = ImageManager::gd();
$generator = new Generator($imageManager);

// Create content with badges
$content = new ImageContent(
    title: 'Getting Started with PHP 8.2',
    description: 'Learn the new features in PHP 8.2 and how to use them',
    badges: [
        new Badge('category', 'PHP'),
        new Badge('level', 'Intermediate'),
    ]
);

// Create a custom theme
$theme = new Theme(
    primaryColor: '#6366f1',
    background: new Background(color: '#0f172a'),
    textColor: '#ffffff',
    mutedColor: '#a0aec0',
    titleFont: new Font('/fonts/bold.ttf', 64, '#ffffff'),
    bodyFont: new Font('/fonts/regular.ttf', 32, '#a0aec0'),
    badgeFont: new Font('/fonts/medium.ttf', 16, '#6366f1'),
    padding: 50,
    logo: '/images/logo.png',
    logoScale: 0.6
);

// Generate the image
$result = $generator->generate(
    data: $content,
    layout: new StandardLayout(),
    theme: $theme,
    format: Format::Webp
);

// Output
echo "Generated OG image: {$result->getWidth()}x{$result->getHeight()}";
echo "MIME Type: {$result->mimeType()}";

// Save to file
file_put_contents('og-image.webp', $result->toString());

// Or get as data URI for HTML img tag
echo '<img src="' . $result->toBase64() . '" />';

Testing

Run the test suite:

composer test

With coverage report:

composer test:coverage

License

MIT License - see LICENSE file for details

Author

Raphael Alogou - raphalogou@gmail.com