Skip to content

OpenDisplay/odl-renderer

Repository files navigation

PyPI version Python versions Lint Testscodecov

odl-renderer

Python renderer for the OpenDisplay Language (ODL).

odl-renderer is a standalone Python library for generating images from ODL drawing instructions. Originally extracted from the OpenEPaperLink Home Assistant integration, it provides a clean, async API for rendering text, shapes, icons, QR codes, and more to PIL images.

Features

  • Pure Rendering: No dependencies on Home Assistant or other frameworks
  • 17 Element Types: Text, shapes, icons, QR codes, images, progress bars, and more
  • Async/Await: Modern async API for efficient image generation
  • Flexible Input: Accepts fonts as PIL objects, file paths, or built-in names
  • Full Color Output: Returns PIL Image objects in full RGB/RGBA (caller handles dithering)
  • Percentage-Based Coordinates: Position elements using percentages or absolute pixels
  • Template-Ready: All values are plain data (templates expanded by caller)

Installation

uv add odl-renderer
# or
pip install odl-renderer

Quickstart

import asyncio
from odl_renderer import generate_image

async def main():
    image = await generate_image(
        width=296,
        height=128,
        elements=[
            {
                "type": "text",
                "value": "Hello World",
                "x": "50%",
                "y": 50,
                "font": "ppb",
                "size": 24,
                "color": "black",
                "anchor": "mm",
            },
            {
                "type": "rectangle",
                "x_start": 10,
                "y_start": 10,
                "x_end": 100,
                "y_end": 50,
                "fill": "red",
                "outline": "black",
                "width": 2,
            },
        ],
        background="white",
        accent_color="red",
    )
    image.save("output.png")

asyncio.run(main())

Element Types

Category Types
Text text, multiline
Shapes rectangle, rectangle_pattern, circle, ellipse, polygon, arc, line
Icons icon, icon_sequence
Media dlimg, qrcode
Visualizations progress_bar, plot, diagram
Debug debug_grid

Reference

Colors

Value Description
"black" / "b" Black
"white" / "w" White
"red" / "r" Red
"yellow" / "y" Yellow
"blue" / "bl" Blue
"green" / "gr" / "g" Green
"gray" / "grey" Mid-gray
"half_black" / "hb" Half-tone black
"half_red" / "hr" Half-tone red
"half_yellow" / "hy" Half-tone yellow
"accent" / "a" Accent color (configured via accent_color param)
"half_accent" / "ha" Half-tone accent
"#RGB" / "#RRGGBB" Hex color

Coordinates

Coordinates accept either absolute integers (10, 256) or percentage strings ("50%", "100%").

When y is omitted, elements stack automatically: each element is placed below the previous one using pos_y + y_padding (default padding: 10px).

Anchors

Used by text, icon, and icon_sequence to set which point of the element aligns to the given x/y coordinates.

text uses PIL anchor format — horizontal axis first, then vertical:

Code Meaning
lt Left-top
mt Middle-top
rt Right-top
lm Left-middle
mm Middle (center)
rm Right-middle
lb Left-bottom
mb Middle-bottom
rb Right-bottom

icon and icon_sequence use a different format for corner anchors — vertical axis first:

Code Meaning
tl Top-left
tr Top-right
mt Middle-top
lm Left-middle
mm Middle (center)
rm Right-middle
bl Bottom-left
br Bottom-right
mb Middle-bottom

The visible field

Every element type accepts an optional visible field. When false, the element is skipped entirely (no rendering, no position update). Defaults to true.

{
    "type": "text",
    "value": "Hidden",
    "x": 10, 
    "y": 10,
    "visible": False
}

Text

text

Single-line text with optional wrapping, truncation, stroke, and inline color markup.

Field Required Default Notes
value yes Text content
x yes X position
y no auto Y position; auto-stacks if omitted
font no "ppb" Built-in name ("ppb", "rbm"), file path, or PIL Font object
size no 20 Font size in pixels
color no "black" Text color
anchor no "lt" / "la" Anchor point; defaults to "la" when text wraps to multiple lines
max_width no Wrap text at this pixel width
truncate no false Truncate with instead of wrapping
align no "left" "left", "center", or "right"
spacing no 5 Line spacing when wrapped
stroke_width no 0 Outline width
stroke_fill no "white" Outline color
parse_colors no false Enable [red]text[/red] inline color markup
y_padding no 10 Extra space above when auto-stacking
{
    "type": "text",
    "value": "Hello",
    "x": "50%",
    "y": 20,
    "size": 32,
    "anchor": "mt",
}

text example

Inline color markup (requires parse_colors: true): wrap text in [color]...[/color] tags. Accepts all named colors, short names, and hex ([#ff0000]red text[/#ff0000]).


multiline

Fixed-line text split by a delimiter, each line placed at a fixed vertical offset.

Field Required Default Notes
value yes Full text content
x yes X position
delimiter yes Character used to split lines (e.g. "|")
offset_y yes Pixels between each line
y no auto Y of first line
font no "ppb" Font
size no 20 Font size
color no "black" Text color
anchor no "lm" Anchor point
align no "left" Text alignment
stroke_width no 0 Outline width
stroke_fill no "white" Outline color
parse_colors no false Inline color markup
{
    "type": "multiline",
    "value": "Line 1|Line 2|Line 3",
    "x": 10,
    "y": 10,
    "delimiter": "|",
    "offset_y": 24,
    "size": 18,
}

multiline example


Shapes

rectangle

Rectangle with optional fill, outline, and rounded corners.

Field Required Default Notes
x_start yes Left edge
y_start yes Top edge
x_end yes Right edge
y_end yes Bottom edge
fill no Fill color
outline no "black" Border color
width no 1 Border width
corners no Which corners to round: "all", "top_left", "top_right", "bottom_left", "bottom_right" (comma-separated)
radius no 10 Corner radius; only applies when corners is set
{
    "type": "rectangle",
    "x_start": 10,
    "y_start": 10,
    "x_end": 100,
    "y_end": 60,
    "fill": "black",
}

rectangle example


rectangle_pattern

Repeating grid of rectangles — useful for dot matrices, grids, and decorative patterns.

Field Required Default Notes
x_start yes Starting X
y_start yes Starting Y
x_size yes Width of each rectangle
y_size yes Height of each rectangle
x_repeat yes Number of columns
y_repeat yes Number of rows
x_offset yes Horizontal gap between rectangles
y_offset yes Vertical gap between rectangles
fill no Fill color
outline no "black" Border color
width no 1 Border width
corners / radius no Same as rectangle
{
    "type": "rectangle_pattern",
    "x_start": 10,
    "y_start": 10,
    "x_size": 8,
    "y_size": 8,
    "x_repeat": 5,
    "y_repeat": 3,
    "x_offset": 4,
    "y_offset": 4,
    "fill": "black",
}

rectangle_pattern example


circle

Circle defined by center point and radius.

Field Required Default Notes
x yes Center X
y yes Center Y
radius yes Radius in pixels
fill no Fill color
outline no "black" Border color
width no 1 Border width
{
    "type": "circle",
    "x": "50%",
    "y": "50%",
    "radius": 20,
    "fill": "green",
    "outline": "black",
}

circle example


ellipse

Ellipse defined by a bounding box.

Field Required Default Notes
x_start yes Left edge
y_start yes Top edge
x_end yes Right edge
y_end yes Bottom edge
fill no Fill color
outline no "black" Border color
width no 1 Border width
{
    "type": "ellipse",
    "x_start": 10,
    "y_start": 10,
    "x_end": 100,
    "y_end": 60,
    "fill": "yellow",
}

ellipse example


polygon

Arbitrary polygon defined by a list of vertices.

Field Required Default Notes
points yes List of [x, y] pairs
fill no Fill color
outline no "black" Border color
{
    "type": "polygon",
    "points": [[10, 50], [50, 10], [90, 50], [50, 90]],
    "fill": "blue",
}

polygon example


arc

Arc or pie slice defined by center, radius, and angle range.

Field Required Default Notes
x yes Center X
y yes Center Y
radius yes Radius in pixels
start_angle yes Start angle in degrees (0 = right, counter-clockwise)
end_angle yes End angle in degrees
fill no Fill color (creates a pie slice)
outline no "black" Border color
width no 1 Border width
{
    "type": "arc",
    "x": 50,
    "y": 50,
    "radius": 30,
    "start_angle": 0,
    "end_angle": 270,
    "outline": "black",
    "fill": "half_red",
}

arc example


line

Straight line between two points with optional dashing.

Field Required Default Notes
x_start yes Start X
x_end yes End X
y_start no auto Start Y
y_end no y_start End Y (horizontal line if omitted)
fill no "black" Line color
width no 1 Line width
dashed no false Enable dashed style
dash_length no 5 Length of each dash
space_length no 3 Gap between dashes
{
    "type": "line",
    "x_start": "10%",
    "y_start": "50%",
    "x_end": "90%",
    "y_end": "50%",
    "fill": "black",
}

line example


Icons

Icons use the bundled Material Design Icons font (7,000+ icons). Pass the icon name with or without the mdi: prefix.

icon

Single MDI icon.

Field Required Default Notes
value yes Icon name, e.g. "home" or "mdi:home"
x yes X position
y yes Y position
size yes Icon size in pixels
color no "black" Icon color
anchor no "mm" Anchor point
{
    "type": "icon",
    "value": "mdi:thermometer",
    "x": "50%",
    "y": "50%",
    "size": 48,
    "anchor": "mm",
}

icon example


icon_sequence

Row or column of MDI icons.

Field Required Default Notes
icons yes List of icon names
x yes Starting X
y yes Starting Y
size yes Icon size in pixels
direction no "right" "right", "left", "up", or "down"
spacing no size / 4 Gap between icons
color no "black" Icon color
anchor no "mm" Anchor point
{
    "type": "icon_sequence",
    "icons": ["mdi:weather-sunny", "mdi:weather-cloudy", "mdi:weather-rainy"],
    "x": 20,
    "y": 20,
    "size": 32,
}

icon_sequence example


Media

dlimg

Image from a URL, file path, data URI, bytes, or PIL Image object. Resized to fit the specified dimensions.

Note: Entity IDs are not resolved — the caller must pass a URL, file path, or image object directly.

Field Required Default Notes
url yes Source: HTTP URL, file path, data URI, bytes, or PIL.Image
x yes X position
y yes Y position
xsize yes Target width
ysize yes Target height
rotate no 0 Rotation in degrees
resize_method no "stretch" "stretch", "crop", "cover", or "contain"
{
    "type": "dlimg",
    "url": "https://picsum.photos/seed/odl/200/150",
    "x": 0,
    "y": 0,
    "xsize": 200,
    "ysize": 150,
    "resize_method": "cover",
}

dlimg example


qrcode

QR code generated from any text or URL.

Field Required Default Notes
data yes QR code content
x yes X position
y yes Y position
color no "black" Foreground color
bgcolor no "white" Background color
border no 1 Quiet zone size in modules
boxsize no 2 Pixel size of each module
{
    "type": "qrcode",
    "data": "https://opendisplay.org",
    "x": 10,
    "y": 10,
}

qrcode example


Visualizations

progress_bar

Horizontal or vertical progress bar with optional percentage label.

Field Required Default Notes
x_start yes Left edge
y_start yes Top edge
x_end yes Right edge
y_end yes Bottom edge
progress yes Fill level 0–100 (clamped automatically)
direction no "right" "right", "left", "up", or "down"
fill no "red" Progress fill color
background no "white" Empty track color
outline no "black" Border color
width no 1 Border width
show_percentage no false Overlay percentage text
font_name no "ppb" Font for percentage text
{
    "type": "progress_bar",
    "x_start": "10%",
    "y_start": 50,
    "x_end": "90%",
    "y_end": 70,
    "progress": 72,
    "fill": "accent",
    "show_percentage": True,
}

progress_bar example


plot

Time-series line chart with configurable axes, grid, and legends. Requires a DataProvider in the drawing context to supply historical data.

Field Required Default Notes
data yes List of series configs (see below)
x_start no 0 Chart left edge
y_start no 0 Chart top edge
x_end no image width Chart right edge
y_end no image height Chart bottom edge
duration no 86400 Time window in seconds
low / high no auto Y-axis range override
font no "ppb" Font for labels
Series, axis, and legend options

Each series in data:

Field Default Notes
entity required Data source identifier passed to DataProvider
color required Line color
width 2 Line width
smooth false Smooth the line
line_style "solid" "solid", "dashed", or "dotted"
show_points false Draw data points
span_gaps false Connect across missing values

yaxis (optional dict):

Field Default
tick_every required
color "black"
grid true
grid_style "dotted"

xaxis (optional dict):

Field Default
color "black"
grid true
grid_style "dotted"

ylegend (optional dict):

Field Default
position "left"
size 10
color "black"

xlegend (optional dict):

Field Default
interval required
format "%H:%M"
position "bottom"
size 10
snap_to_hours true
{
  "type": "plot",
  "x_start": 0,
  "y_start": 6,
  "x_end": 292,
  "y_end": 120,
  "round_values": True,
  "data":
    [
      {
        "entity": "sensor.temperature",
        "color": "red",
        "width": 2
      }
    ],
  "yaxis":
    {
      "tick_every": 2,
      "grid_color": "gray"
    },
  "ylegend":
    {
      "position": "left"
    },
  "xaxis":
    {
      "color": "black",
      "grid": False
    },
  "xlegend":
    {
      "interval": 14400
    }
}

plot example


diagram

Simple bar chart with labeled axes.

Field Required Default Notes
x yes X position
height yes Diagram height
width no image width Diagram width
margin no 20 Margin from edges
bars no Bar chart config (see below)

bars config:

Field Notes
values Semicolon-separated "label,value" pairs: "Mon,10;Tue,20;Wed,15"
color Bar fill color
font Font name
legend_size Label font size
legend_color Label color
{
    "type": "diagram",
    "x": 0,
    "height": 128,
    "bars": {
        "values": "Mon,10;Tue,20;Wed,15",
        "color": "black",
    },
}

diagram example


Debug

debug_grid

Renders a coordinate grid over the image. Useful during layout development.

Field Required Default Notes
spacing no 20 Grid cell size in pixels
line_color no "black" Grid line color
dashed no true Use dashed lines
dash_length no 2 Dash segment length
space_length no 4 Gap between dashes
show_labels no true Show coordinate labels
label_step no spacing * 2 Interval between labels
label_color no "black" Label color
label_font_size no 12 Label font size
font no "ppb" Font for labels
{
    "type": "debug_grid",
    "spacing": 20,
    "line_color": "gray",
}

debug_grid example

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages