Skip to content

image://

Producer-only image component — the discoverable home for turning other content into a raster image (PNG / JPEG). Two operations today:

  • op=screenshot (default) — rasterize an HTML body to a PNG/JPEG via headless Chromium (chromedp page.CaptureScreenshot). Highest fidelity: Tailwind, web fonts, complex CSS. Requires a chromium / google-chrome binary on PATH at runtime.
  • op=rasterize — render a page of a PDF body to a PNG/JPEG via pdfium (via klippa-app/go-pdfium, WebAssembly — no CGO, no browser). The Chrome-free path for page previews / thumbnails.

Output is image bytes on the exchange body (Content-Type: image/png or image/jpeg), ready for a file:// write or an HTTP response.

The heavy engines are shared with pdf:// and vlm:// via pkg/component/internal: chromerender (the headless-Chromium round-trip, also used by pdf:// mode=chrome) and pdfiumpool (one process-wide PDFium WASM pool, also used by pdf:// op=fillForm and vlm://).

Producer-only — CreateConsumer returns ErrNoConsumer.

When to use which

You have… …and want a Use
HTML (Tailwind / CSS / charts) high-fidelity PNG/JPEG image://?op=screenshot
an existing PDF page thumbnail / preview, no browser image://?op=rasterize
a structured doc, no Chromium image, fully pure-Go pdf://?op=create&mode=native → image://?op=rasterize
HTML a PDF (not an image) pdf://?mode=chrome

URI shape

image://<name>?op=screenshot&width=1200&height=800&deviceScaleFactor=2&format=png
image://<name>?op=screenshot&fullPage=true&format=jpeg&quality=85
image://<name>?op=rasterize&page=1&dpi=150&format=png

Omitting op= defaults to screenshot.

Parameters

General (both ops)

Param Type Default Description
op enum screenshot screenshot (HTML→image, Chromium) or rasterize (PDF page→image, pdfium).
format enum png Output image format: png or jpeg.
quality integer 90 JPEG compression quality [0..100]; ignored for png.

screenshot (Chromium)

Param Type Default Description
width integer 1200 Viewport width in CSS px.
height integer 800 Viewport height in CSS px. With fullPage=true the captured height grows to the whole page.
deviceScaleFactor number 1 Device pixel ratio; 2 = retina / 2× output resolution.
fullPage boolean false Capture the whole scrollable page instead of just the viewport.
chromePath string autodiscover Explicit Chromium / Chrome binary path.
timeout duration 30s Render timeout.
waitSelector string — Wait for a CSS selector to appear before capturing.
waitMs integer — Fixed wait in milliseconds before capturing (use sparingly).

rasterize (pdfium)

Param Type Default Description
page integer 1 1-indexed PDF page to render. Out-of-range errors.
dpi integer 150 Render resolution in DPI; output pixel size ≈ pageSize(in) × dpi.

Body contracts

  • op=screenshot — the body must be HTML: a string or []byte. It is loaded as a data:text/html;charset=utf-8,… URL and captured.
  • op=rasterize — the body must be PDF bytes: a []byte, a string, or an io.Reader whose content contains the %PDF- magic. A non-PDF body is rejected up front.

Headers (written)

Header Description
Content-Type image/png or image/jpeg.
image.op Operation that ran (screenshot / rasterize).
image.format png or jpeg.
image.bytes Output size in bytes.
image.page (rasterize) The 1-indexed page rendered.
image.width, image.height (rasterize) Output pixel dimensions.

The body is set to the image []byte; the exchange's In() body is also overwritten so the next pipeline step sees the image.

Examples

Screenshot an HTML poster to a retina PNG and write it to disk:

workflows:
  - id: poster
    trigger: { uri: direct://render }
    steps:
      - set-body: { starlang: payload.html }          # an HTML string
      - target: image://poster?op=screenshot&width=1080&height=1080&deviceScaleFactor=2&format=png
      - set-header: { name: HelixFileName, constant: poster.png }
      - target: file:///var/out                        # default op=write

Return a screenshot straight over HTTP (image bytes become the response body):

  - id: og-image
    trigger: { uri: http-server://0.0.0.0:8080/og }
    steps:
      - set-body: { starlang: payload.html }
      - target: image://og?op=screenshot&width=1200&height=630&format=png

Full-page JPEG capture (whole scrollable page, not just the viewport):

- target: image://cap?op=screenshot&fullPage=true&format=jpeg&quality=85

Wait for an async chart to render before capturing:

- target: image://chart?op=screenshot&waitSelector=.chart-ready&width=900&height=600

Thumbnail page 1 of an uploaded PDF — pure-Go, no Chromium:

  - id: pdf-thumb
    trigger: { uri: "file:///var/in?include=.*\\.pdf" }
    steps:
      - target: image://thumb?op=rasterize&page=1&dpi=120&format=png
      - set-header: { name: HelixFileName, starlang: 'headers["HelixFileName"] + ".png"' }
      - target: file:///var/thumbs

Structured content → image with no browser at any step (native PDF, then pdfium raster):

- set-body:
    starlang: |
      { "title": "Weekly Report", "text": "Generated without a browser." }
- target: pdf://doc?op=create&mode=native      # fpdf → PDF bytes (pure-Go)
- target: image://page?op=rasterize&dpi=150    # pdfium → PNG bytes (pure-Go)

Behavior notes

  • screenshot needs Chromium; rasterize does not. Only arbitrary-HTML rasterization is browser-bound — there is no pure-Go engine that renders modern HTML/CSS at fidelity. Every PDF/structured path to an image (rasterize, or pdf://mode=native → rasterize) is pure-Go.
  • fullPage sets CaptureBeyondViewport — the capture extends past the viewport to the full document height. Without it you get exactly width × height (× deviceScaleFactor) pixels.
  • deviceScaleFactor multiplies the raster resolution: a 400×300 viewport at deviceScaleFactor=2 yields an 800×600 image.
  • rasterize draws the form layer (RenderForm), so filled AcroForm field values appear in the raster — the same rendering vlm:// uses.
  • Shared engines — screenshot runs the same chromerender round-trip as pdf://mode=chrome; rasterize uses the same process-wide pdfium pool as pdf://op=fillForm and vlm://. One Chromium launch path, one WASM module.
  • Both ops overwrite the In() body — the next pipeline step sees the image bytes, not the HTML / PDF input.

Source

  • pkg/component/image/image.go — component, endpoint, param parsing, op dispatch.
  • pkg/component/image/screenshot.go — op=screenshot (chromerender).
  • pkg/component/image/rasterize.go — op=rasterize (pdfiumpool).
  • pkg/component/internal/chromerender/render.go — shared headless-Chromium round-trip.
  • pkg/component/internal/pdfiumpool/pool.go — shared PDFium WASM pool.

See also

  • pdf — HTML→PDF (mode=chrome) and structured→PDF (mode=native); pair mode=native with image://op=rasterize for a browser-free content→image path.
  • chart — native chart rendering (render a chart, drop it into HTML, screenshot the result).
  • template — build the HTML you feed into op=screenshot.
  • vlm — shares the same pdfium engine to rasterise PDF pages for vision models.
  • file, s3 — common downstream sinks for the rendered image.