feat: true no-X headless --render (CPU spectrogram bitmap + overlay)
Rewrite --render to compute the spectrogram and write a PNG entirely on the CPU, with no window, no GL context, and no X server. Previously it opened a hidden GL window and grabbed LoadImageFromScreen(), which still required an X server (Xvfb); the output was a UI screenshot rather than the spectrogram data. The new path (RunHeadlessRender) loads the WAV, computes the STFT, colorizes the bitmap at native STFT resolution, bakes the mLnL annotation overlay onto it, and exports — all CPU-only. render.c gains a GL-free colorize (BuildSpectrogramImageCPU), a CPU font loader (LoadFontCPU), and a CPU overlay drawer (DrawAnnotationsToImage). Annotations draw outline + label only: mLnL captures contain many overlapping full-band boxes whose translucent fills alpha-stack to opaque and bury the signal. The outline marks each region while the spectrogram reads through; a dark backing strip keeps labels legible. Note: MeasureTextEx/ImageText* bail when font.texture.id == 0, so the CPU font sets a sentinel non-zero id (the draw path reads glyph images, never the texture). Render options: --annotation-opacity (overlay strength), --annotation-kinds (comma-separated kind filter), --width (resize; default native). Removed the obsolete --pane/--height window options and the screenshot workaround. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,21 @@ Trigger it from a temp keybinding or a `--shoot-after N frames` flag. This bypas
|
||||
ImageMagick entirely and is the exact framebuffer — preferable when you can edit code
|
||||
(which, in a refactor task, you already are).
|
||||
|
||||
**C. A true no-display render path (if the app has one).** The strongest option when
|
||||
you only need to verify *output* (not the live UI): a CLI mode that computes the frame
|
||||
and writes a PNG entirely on the CPU, never calling `InitWindow` — so it needs **no
|
||||
Xvfb, no GL, no X server at all**. raylib's `Image` API (`GenImageColor`, `ImageDraw*`,
|
||||
`ImageDrawTextEx`, `ExportImage`) is pure CPU; only `Texture*`/`Draw*`/`BeginDrawing`
|
||||
need a GL context. So a headless path can reuse the real pixel/colorize/annotation code
|
||||
and skip the window. (One trap: `MeasureTextEx`/`ImageText*` short-circuit to zero when
|
||||
`font.texture.id == 0`, so a CPU-loaded font — `LoadFontData` + `GenImageFontAtlas`, no
|
||||
upload — must set a sentinel non-zero `texture.id` to draw text.)
|
||||
|
||||
> **This repo** has exactly that: `rspektrum --render OUT.png INPUT.wav` (see
|
||||
> `RunHeadlessRender` in `spectrogram.c`). Use it to check spectrogram/annotation output
|
||||
> with no display. The Xvfb loop below is still needed to exercise the *interactive* GUI
|
||||
> (clicks, drags, hover tooltips, the live sidebar) — things the static render can't show.
|
||||
|
||||
Then **look at it**: open the PNG with your image-reading tool. Vision catches "the HUD
|
||||
vanished" or "text is now black-on-black" that a pixel count won't explain.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user