No project description provided
Project description
Poster Generator
A lightweight flexible Python library for building and rendering graphics with support for layers, groups, and YAML-based templates.
Features
• 🧱 Layering system for Z-order control and basic blend settings leveraging [Pillow](https://python-pillow.org/)
• 🗂️ Optional groups for quick categorization or batch selection
• 📄 YAML templates with variable substitution for reusable layouts
• 🎯 Anchors & relative positioning for layout-style placement
• 🔌 Extensible, format-agnostic registry for custom elements and operations
• 🛠️ Function-driven operations (e.g., hue shifting, scaling, transforms)
• 📣 Designed for automated poster and social media generation
⸻
Installation
Using Poetry (recommended)
poetry add poster-generator
Using pip
pip install poster-generator
From source
git clone https://github.com/corgi-in-tights/poster-generator.git
cd poster-generator
poetry install
Quick Start
Programmatic Usage
Create a simple poster with text and image elements:
from pathlib import Path
from poster_generator import Canvas, TextElement, ImageElement
from poster_generator.operations.image import apply_hue_shift
# Create a canvas
canvas = Canvas(width=1080, height=1350, background="#c75d5d")
# Add an image with hue shift
background = ImageElement(
(0, 0),
image_path="path/to/image.png",
width=1080,
height=1350,
)
background.apply_operation(lambda img: apply_hue_shift(img, 30))
canvas.add_element("background", background)
# Add text
text = TextElement(
(50, height//2 - 64),
text="Hello, Poster!",
font_size=64,
color="#333333",
)
canvas.add_element("title", text)
# Render and save
image = canvas.render()
image.save("output.png")
YAML Template Usage
Define your poster in a YAML template:
---
schema: "1.0"
settings:
width: 1080
height: 1350
background_color: "#f295df"
anchors:
top_left:
x: 50
y: 50
layers:
background:
settings:
opacity: 1.0
elements:
bg_image:
type: image
position: [0, 0]
operations:
apply_hue_shift:
degrees: --${hue_shift}--
values:
image_path: --${background_image}--
width: 1080
height: 1350
text:
elements:
title:
type: text
rel_position:
source: anchor
id: top_left
values:
text: --${title_text}--
font_size: 64
color: "#FFFFFF"
subtitle:
type: text
rel_position:
source: element
id: title
offset:
x: 0
y: 50
values:
text: My subtitle :)
font_size: 30
color: "#FFFFFF"
Load and render the template:
from poster_generator.loaders import YamlLoader
loader = YamlLoader()
canvas = loader.build_canvas(
"template.yml",
variables={
"hue_shift": 45,
"title_text": "My Poster",
"background_image": "background.png",
}
)
image = canvas.render()
image.save("output.png")
Core Concepts
Canvas
The Canvas is the main container for your poster. It manages elements, layers, and rendering.
canvas = Canvas(width=1080, height=1350, background="#ffffff")
Elements
Elements are the building blocks of your poster:
- TextElement: Renders text with custom styling
- ImageElement: Renders images with transformation support
# Text element
text = TextElement(
position=(100, 100),
text="Hello World",
font_size=48,
color="#000000"
)
# Image element
image = ImageElement(
position=(0, 0),
image_path="image.png",
width=500,
height=500
)
Layers
Layers help organize elements and control rendering order:
canvas.add_element("bg", background, layer="background")
canvas.add_element("title", text, layer="foreground")
Groups
Groups allow you to manage related elements:
canvas.add_element("title", text, groups=["headers", "top-section"])
canvas.add_element("subtitle", subtitle, groups=["headers", "top-section"])
# Query elements by group
headers = canvas.get_elements(groups="headers")
Operations
Apply transformations to elements:
from poster_generator.operations.image import apply_hue_shift, set_hue_from_hex
# Hue shift
element.apply_operation(lambda img: apply_hue_shift(img, degrees=45))
# Set hue from color
element.apply_operation(lambda img: set_hue_from_hex(img, "#FF5733"))
Advanced Usage
Custom Element Types
Register your own element types using the factory pattern:
from poster_generator.elements import DrawableElement, register_element_type
class CustomElement(DrawableElement):
def __init__(self, position, custom_param=None):
super().__init__(position)
self.custom_param = custom_param
def draw(self, draw, image, blend_settings: dict):
# Your drawing logic
pass
def is_ready(self):
return True
def overlaps_region(self, x1, y1, x2, y2):
return False
def apply_operation(self, operation):
pass
# Register the custom element
register_element_type("custom", CustomElement)
Element Queries
Query elements by identifier, group, or layer:
# Get specific elements
elements = canvas.get_elements(identifiers=["title", "subtitle"])
# Get by group
headers = canvas.get_elements(groups="headers")
# Get by layer
bg_elements = canvas.get_elements(layers="background")
# Combine filters (require all)
specific = canvas.get_elements(
groups="headers",
layers="foreground",
require_all=True
)
YAML Variable Substitution
Use --${variable_name}-- syntax in YAML templates:
values:
text: --${title}--
font_size: --${size}--
color: --${color}--
canvas = loader.build_canvas(
"template.yml",
variables={
"title": "My Title",
"size": 48,
"color": "#FF0000"
}
)
Relative Positioning
Position elements relative to anchors or other elements:
# Relative to anchor
rel_position:
source: anchor
id: top_left
offset:
x: 20
y: 30
# Relative to another element
rel_position:
source: element
id: title
offset:
x: 0
y: 50
API Reference
Canvas
Canvas(width, height, background)- Create a new canvas with specified dimensions and background coloradd_element(identifier, element, groups=None, layer="default")- Add an element to the canvas with a unique identifier, optional groups, and layer assignmentremove_element(identifier)- Remove an element from the canvas by its identifierget_elements(identifiers=None, groups=None, layers=None, require_all=False)- Query and retrieve elements by identifiers, groups, or layers. Setrequire_all=Trueto match all criteriaclear_layer(layer)- Clear all elements from a specific layerclear_group(group)- Clear all elements belonging to a specific groupcrop(x1, y1, x2, y2)- Crop the canvas to the rectangular region defined by coordinates (x1, y1) as top-left and (x2, y2) as bottom-rightalign_element(identifier, x_align, y_align)- Set an element's position to a specific canvas-based alignment (e.g., 'center', 'left', 'right', 'top', 'bottom')render(global_op=None)- Render the canvas to an image, optionally applying global operationsfrom_dict(data)- Create and populate a canvas from a dictionary representation
TextElement
TextElement(position, text=None, font_path=None, font_size=20, color="#000")- Create text elementdraw(draw, image, position=None)- Draw the textis_ready()- Check if ready to render
ImageElement
ImageElement(position, image_path=None, width=None, height=None)- Create image elementload_image(image_path)- Load an image fileapply_hue_shift(degrees)- Shift image hueset_hue_from_hex(hex_color)- Set hue from colorapply_operation(operation)- Apply transformationdraw(draw, canvas_image, position=None)- Draw the imageis_ready()- Check if ready to render
YamlLoader
YamlLoader()- Create YAML loaderbuild_canvas(source, variables=None)- Build canvas from YAML file or dict
Examples
Check out the examples/ directory for more complete examples:
examples/basic.py- Programmatic poster creationexamples/yml.py- YAML template loadingexamples/templates/my_template.yml- Example YAML template
Requirements
- Python >= 3.13
- Pillow >= 12.0.0
- PyYAML >= 6.0.3
Development
Setup
# Clone the repository
git clone https://github.com/corgi-in-tights/poster-generator.git
cd poster-generator
# Install dependencies
poetry install
# Run examples
poetry run python examples/basic.py
poetry run python examples/yml.py
Project Structure
poster_generator/
├── ...
├── canvas.py # Canvas class
├── elements/ # Element implementations
│ ├── drawable.py # Base element class
│ ├── text.py # Text element
│ ├── image.py # Image element
│ └── factory.py # Element factory
├── loaders/ # Template loaders
│ ├── base.py # Base loader
│ └── yaml_loader.py # YAML loader
└── operations/ # Image operations
├── ...
└── factory.py # Operation factory
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. I am open to significant design changes if they match the project's intention.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Issues
I cannot guarantee this project will be actively maintained since there really isn't much to add from my end. The current end product fulfills my rather primitive needs -- however, if any critical bugs come up, please open a GitHub issue.
If there are architectural issues (i.e. inflexible code), then please feel free to open an issue, but for additional features, a PR would be much preferred.
Acknowledgments
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file poster_generator-1.1.0.tar.gz.
File metadata
- Download URL: poster_generator-1.1.0.tar.gz
- Upload date:
- Size: 366.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ba08fd1260ee53dd97842138206d4f1b26a45392d82e1c4ebe3a3b9ac5e491d
|
|
| MD5 |
1782a52be63ec9443c8da622c79d3e14
|
|
| BLAKE2b-256 |
7d4ded8732ffe9114c312a6e7e07a8565f8dd3171bc682301fb07f7edb2ba9fd
|
File details
Details for the file poster_generator-1.1.0-py3-none-any.whl.
File metadata
- Download URL: poster_generator-1.1.0-py3-none-any.whl
- Upload date:
- Size: 367.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c6e17122e2dc54d937b5c4ca63efeb791293e3d546032f7d87a3b3a27183e351
|
|
| MD5 |
21dd0092aa5241019a5b5942d5174447
|
|
| BLAKE2b-256 |
464087cc66982182c9728c41596ff6a1454ab7f8ece38225f1901ffb03900164
|