Skip to content

Screenshots

NuclearMeltdown edited this page Aug 25, 2026 · 2 revisions

Screenshots

src/record/screenshot.cpp, src/render/video_renderer.cpp (GrabStill, GrabStillHalf), src/render/d3d_context.cpp (GrabBackBuffer)

F10 by default. Written at source resolution, after crop, deinterlacing and rotation, and before the interface is drawn — so no toolbar, no statistics overlay, no toast in the picture. Include the interface in the Recording tab moves the grab to the other side of that line; see below.

SDR: PNG and JPEG

Through Windows Imaging Component, which ships with Windows. A screenshot is the one output that should work on a fresh machine where nobody has pressed the ffmpeg download button yet.

GrabStill() copies the current picture out once, tightly packed, in VideoRenderer::kReadbackPixelFormat. Unlike the recording path this waits for the GPU, which costs a millisecond or two — acceptable for a key press, not for every frame. Alpha comes back opaque. It must be called on the render thread.

HDR: JPEG XR and AVIF

Only offered when the source is actually HDR and the "keep the range" switch for screenshots is on. See High dynamic range.

GrabStillHalf() returns the picture as linear light, four half floats per pixel, 1.0 meaning diffuse white.

JPEG XR (.jxr)

SaveScreenshotHdr(). Holds scRGB half floats, which is exactly what Windows itself writes for an HDR screenshot — and therefore what the Photos app opens as one rather than as a dark mess.

Costs nothing: Windows ships the encoder, so this is the HDR format that can be written on a machine where nobody has pressed the download button. AVIF, below, is the one screenshot format that cannot.

paperWhiteNits is passed in because scRGB fixes its own 1.0 at eighty nits, so the linear values have to be scaled into that convention.

AVIF

SaveScreenshotAvif(). Ten bit PQ in BT.2020, with the colour description that makes it an HDR image rather than a dark one.

Read by every browser and by most things that are not Windows — but it goes through ffmpeg. Since ffmpeg is already there for recording that is not a new dependency, only a newly required one, and the format picker says so.

Why not 16-bit PNG

Nothing would know to read it as HDR. PNG has no place to say "this is on the PQ curve" that any viewer acts on, so a 16-bit PNG of HDR content is a file full of correct numbers that every program displays wrongly.

Including the interface

RenderFrame has two grab points, and the setting decides which one fires.

The default is immediately after renderer_.Draw() and before ImGui_ImplDX11_NewFrame(), which is why nothing of the interface can reach the file. The other is after the draw data has been rendered and before d3d_.EndFrame() — the only moment the back buffer holds the finished window, since under the flip model its contents are undefined once the present has happened.

D3DContext::GrabBackBuffer() reads it through a staging texture and swizzles BGRA to RGBA. Alpha is set rather than carried over: what looks opaque on screen has to be opaque in the file.

Two consequences worth knowing before turning it on:

  • The result is the size of the window, not of the source. It is the scaled picture, letterboxing included, not the source pixels.
  • It is always SDR. With HDR output the back buffer is scRGB in half floats, and converting that to SDR unverified would mean shipping untested colour maths, so the grab is refused, the picture alone is saved instead, and the message says so.

A separate settings window is its own top-level window with its own swapchain, so it does not appear either way. The embedded panel does.

File naming

MakeScreenshotPath() builds a timestamped name in the configured folder, with a counter appended when the same second is hit twice. It creates the folder if necessary and returns empty when it cannot.

MakeHdrScreenshotPath() is the same for the two HDR formats.

The default folder is Pictures\CapView (DefaultScreenshotFolder()).

Clone this wiki locally