Eranol LogoEranol
BlogCommunityDocumentationPricingSign In

General

OverviewGet Started

MCP Connectors

ClaudeChatGPTGeminiGrok
Instagram PublishInstagram Scheduled — CancelInstagram Scheduled — ListLinkedIn Cancel ScheduledLinkedIn PublishLinkedIn Scheduled PostsLinkedIn StatusTikTokTikTok Scheduled — CancelTikTok Scheduled — ListTikTok StatusX PublishX Scheduled — CancelX Scheduled — ListYouTube PublishYouTube Scheduled — CancelYouTube Scheduled — List
Add IntroAdd OutroAnimateAudio to VideoBackground AudioCaptions ApiComposeConcatConvert a video file to MP4Convert Audio to Mp3Convert Audio to wavConvert to JPGConvert to WebMConvert to WebPCutDenoiseEnhanceExtract audio track from a videoExtract images from a videoGenerate a GIF from a videoHighlightsImage RenderImages to PDFMedia UploadMergeNotifyOverlayProgress BarReframeRemove SilenceThumbnailTrimVerifyWatermarkZoom
DeleteImage StatusStatusFFmpeg Results

Need help?

Contact Support

Image Render

POST

Render infographic scenes as PNG images, one per scene, in portrait, square or story sizes. Ideal for LinkedIn and Instagram carousels

Overview

Render infographic scenes as still PNG images, one image per scene. Use it to build LinkedIn or Instagram carousels, then combine the images with /convert/images/to/pdf for a PDF carousel.

Colours and font sizes can be customised with an optional style object, for the whole request or for individual scenes.

This is an async job: the request returns a job_id immediately. Poll the status URL until the job is completed, then read the image URLs from the result.

Endpoint

POST https://eranol.com/api/v1/ffmpeg/image/render

Flow

  1. POST /api/v1/ffmpeg/image/render returns a job.
  2. Poll GET /api/v1/ffmpeg/status/{job_id} every 1–2 seconds until status is completed, failed or cancelled. While queued, progress shows Queued — N job(s) ahead.
  3. When completed, read result.images (or call GET /api/v1/ffmpeg/result/{job_id}).
  4. Download the PNGs into your own storage. Hosted files are deleted after 24 hours.

Request Body

{
  "size": "portrait",
  "style": {
    "background": "#fcfcfc",
    "title_size": 72
  },
  "scenes": [
    {
      "template": "stat_countup",
      "kicker": "THE NUMBER",
      "title": "Up to",
      "value": 100000,
      "prefix": "£",
      "bar_max": 100000,
      "accent": "orange"
    },
    {
      "template": "ring_percent",
      "title": "Who is at fault",
      "percent": 46,
      "label": "AT FAULT",
      "style": { "accent_color": "#e46030" }
    }
  ]
}

Unknown top-level fields, unknown scene fields and unknown style fields are rejected with 422.

Parameters

NameTypeDefaultDescription
scenesarrayrequired1 to 80 scenes, one image each, in order
sizestringportraitportrait, square or story
styleobjectnoneColours and font sizes for every scene (see Styling)

size

ValuePixelsUse
portrait1080×1350 (4:5)LinkedIn / Instagram feed
square1080×1080Square posts
story1080×1920Stories

Common scene fields

NameTypeDefaultDescription
templatestringrequiredPicks the layout (see below)
kickerstring''Small uppercase line above the title (max 38 chars)
titlestring''Headline (max 56 chars)
subtitlestring''Grey line under the title (max 90 chars)
accentstringblueblue, green, purple or orange
illustrativeboolfalsePrint the ILLUSTRATIVE SHAPE · NO REAL DATA tag
styleobjectnoneColours and font sizes for this scene only. Overrides the request-level style
footnotestring''Small note at the bottom of the slide (max 140 chars)
sourcestring''Source line under the footnote (max 80 chars). Source: is added for you, so send gov.uk, 2026

Leave start, end and every at field out. For images the server picks the timing and captures each slide settled.

Templates

TemplateRequiredOptional
stat_countupvalue (0–1e12)prefix (max 4), suffix (max 6), decimals (0–2), label (max 40), bar_max (at least value), icon
hbar_comparebars (2–4 of {label max 24, value_text max 14, ratio 0–1, accent?})hero {value, prefix, suffix, decimals}
ring_percentpercent (0–100)label (max 20), stamp {text max 24}
rowsitems (2–5 of {text max 44, state: "keep" or "reject"})
bar_columnscolumns (3–12 of {label max 4, value_text max 8})note (max 24)
growing_barscount (4–10), left_label (max 20), right_label (max 28)
progress_tracklabel (1–30 chars)direction (fill or drain), text (max 20)
icon_pairicons (1–3 of {name, caption max 40, accent?})symbol (max 2 chars), numbered, stamp {text}
logo_flowlogo_domain (bare domain, e.g. mod.uk)to_icon, arrow
headline_quotequote (1–120 chars)highlight (text from the quote, shown in the accent colour, max 60), sub (max 90), rule (accent line above, default true), marks (wrap in quotation marks, default true)
timelineevents (2–6 of {date max 24, label max 24, key?})
stacked_columnsegments (2–6 of {label max 36, value ≥ 0, value_text? max 10}, top to bottom)
pie_chartslices (2–6 of {label max 24, value ≥ 0, accent?}; values must add up to more than 0)donut (default true; false draws a full pie), center_text (donut only, max 12)
line_chartx_labels (2–12, each 1–6 chars), series (1–3 of {name max 20, values one per x label, accent?})y_prefix, y_suffix (max 4 each)
bar_chartbars (2–8 of {label max 12, value ≥ 0, value_text? max 12, tone? strong/light/muted, accent?})side (2–5 segments {label, value, value_text?} shown as a stacked block on the right)
hbar_chartrows (2–8 of {label max 20, value ≥ 0, value_text? max 12, tone?, accent?})

How the new templates behave:

  • headline_quote: a large left-aligned statement for hook and takeaway slides. Put \n in the quote to force a line break (for example "Cheap plans\ncan cap\nyour invoices"); the text size steps down automatically for longer quotes. highlight must appear in quote exactly, otherwise the request returns 422.
  • timeline: milestones on a horizontal line, date above and label below. key: true events use the accent colour; the others are tinted.
  • stacked_column: one tall column whose segment heights follow value (small segments are kept tall enough to read). Each segment gets a leader line to its label and its text colour is chosen for contrast. Shades run light to dark from the accent colour.
  • bar_chart: vertical bars scaled to the largest value, with the value above each bar. Give one bar an accent (for example orange) to highlight it, and use tone: "light" or "muted" for the others. Spacing and label size tighten automatically as bars are added. side adds a stacked block on the right.
  • hbar_chart: horizontal bars from a left axis, with the label on the left and the value after the bar. A row with value 0 shows just its label and value.
  • pie_chart: slice shades come from the accent colour unless a slice names its own accent. The legend shows whole-number percentages that add up to 100.
  • line_chart: the y axis starts at 0 (and goes below it if a value is negative) with tidy tick values. The last value of each series is labelled, and a legend appears when there is more than one series.

Icon names are Lucide names such as shield-check. An unknown name fails validation with 422. Logos are looked up by domain; if one isn't found the slide renders without it. When any logo is used, an attribution line is printed on the last slide.

Styling

The optional style object changes colours, font sizes and the title weight. It can be set on the request (applies to every scene) and on any scene (applies to that scene only and wins over the request-level value). Fields you leave out keep the default look, and a request with no style renders exactly as it always has.

style changes appearance, not layout. Each template keeps its structure; to get a different layout, use a different template.

Colours

All colours are #RRGGBB hex strings (for example #e46030).

FieldChanges
backgroundThe slide background
text_colorTitles, axis and column labels, and the number badges on icon_pair
muted_colorRow text on rows, and the credit and illustrative tag lines
label_colorCaptions (on ring_percent) and bar labels (on hbar_compare, progress_track)
alert_colorStamps and the strike-through on rejected rows items
accent_colorReplaces the scene's accent: the kicker, bars, rings, tiles and hero numbers. Items that name their own accent (for example a bar in hbar_compare) keep it

Font sizes and weight

Sizes are whole numbers in pixels, on the 1080-wide canvas.

FieldRangeChanges
title_size24–160The scene title
quote_size40–220The headline_quote text. By default it steps down with the quote's length (136, 108, 86 or 68 px)
title_weight400, 500, 600, 700, 800 or 900The scene title weight
kicker_size16–90The small uppercase line above the title
caption_size16–90Captions on ring_percent and icon_pair tiles
label_size16–90Bar labels, column labels, axis labels, and timeline dates and stacked-column labels
value_size24–240The centre number of ring_percent, the note on bar_columns, the segment values on stacked_column, the donut's center_text and the end labels on line_chart

Large numbers elsewhere (the count-up number on stat_countup and hbar_compare, bar values, stamp text) are sized automatically to fit their text and are not changed by value_size.

Rules

  • Values are validated. A colour that is not #RRGGBB, a size outside its range, or an unknown field returns 422.
  • Raw CSS is not accepted.
  • Scene-level style is merged over request-level style field by field. A scene that sets only accent_color still gets the request's background.

Example

A dark-on-cream look for the whole carousel, with one orange slide:

{
  "size": "square",
  "style": {
    "background": "#fcfcfc",
    "text_color": "#14171c",
    "accent_color": "#2472c6",
    "title_size": 76,
    "title_weight": 800
  },
  "scenes": [
    { "template": "stat_countup", "kicker": "THE NUMBER", "title": "Claims paid", "value": 4200, "prefix": "£" },
    { "template": "ring_percent", "title": "Who is at fault", "percent": 46, "label": "AT FAULT",
      "style": { "accent_color": "#e46030" } }
  ]
}

Response Example

[
  {
    "job_id": "1406c589-a1f4-45d5-8745-aae07bc4de38",
    "status": "pending",
    "message": "Job created. Poll status_url for progress.",
    "result_url": "https://eranol.com/api/v1/ffmpeg/result/1406c589-a1f4-45d5-8745-aae07bc4de38",
    "status_url": "https://eranol.com/api/v1/ffmpeg/status/1406c589-a1f4-45d5-8745-aae07bc4de38"
  }
]

Completed result

{
  "images": [
    { "index": 1, "url": "https://ffmpeg.eranol.com/outputs/<uuid>.png", "filename": "<uuid>.png" }
  ],
  "filenames": ["<uuid>.png"],
  "count": 4,
  "format": "png",
  "resolution": "1080x1350",
  "size": "portrait",
  "logos_used": ["mod.uk"]
}

images is in the same order as scenes.

Use Cases

1. LinkedIn carousel

Four portrait slides, then pass the image URLs to /convert/images/to/pdf for a PDF carousel.

Request Body

{
  "size": "portrait",
  "scenes": [
    { "template": "stat_countup", "kicker": "THE NUMBER", "title": "Claims paid", "value": 4200, "prefix": "£" },
    { "template": "hbar_compare", "title": "Fault split", "bars": [
      { "label": "Driver A", "value_text": "62%", "ratio": 0.62 },
      { "label": "Driver B", "value_text": "38%", "ratio": 0.38, "accent": "orange" }
    ] },
    { "template": "rows", "title": "Do and don't", "items": [
      { "text": "Photograph the scene", "state": "keep" },
      { "text": "Admit fault", "state": "reject" }
    ] },
    { "template": "logo_flow", "title": "Report it to", "logo_domain": "gov.uk", "arrow": true }
  ]
}

2. Instagram story

A single 1080×1920 slide.

Request Body

{
  "size": "story",
  "scenes": [
    { "template": "ring_percent", "title": "Who is at fault", "percent": 46, "label": "AT FAULT", "accent": "purple" }
  ]
}

3. Branded carousel

The same slides in your brand colours: one style on the request, no per-scene changes.

Request Body

{
  "size": "portrait",
  "style": {
    "background": "#f4f7fb",
    "text_color": "#0c122a",
    "accent_color": "#0666c0",
    "title_size": 72,
    "kicker_size": 26
  },
  "scenes": [
    { "template": "stat_countup", "kicker": "THE NUMBER", "title": "Claims paid", "value": 4200, "prefix": "£" },
    { "template": "ring_percent", "title": "Who is at fault", "percent": 46, "label": "AT FAULT" }
  ]
}

Notes

  • Jobs run one at a time, so requests may queue. progress shows Queued — N job(s) ahead.
  • If a job failed, the same request can be retried.
  • Hosted images are deleted after 24 hours. Download them right after completion.

Pricing

1 credit per request (Standard Plan), regardless of the number of scenes.

Error Codes

CodeMeaning
401Missing or invalid API key
402Insufficient credits
422Validation error — loc names the offending field (e.g. unknown field or icon, invalid style colour or size, too many scenes)
429Rate limit exceeded — slow down requests
500Internal server error — try again or contact support