OSC 533 Screenshot
A proposal for a program to ask its terminal for a region of the screen, as text, as VT sequences, or as an image.
OSC 533 ; top ; left ; bottom ; right ; format ST
- Specification
- VT sequence: screenshot, Contour issue #161
Screenshot lets a program ask its terminal for what is on the screen: a rectangle of it, returned as plain text, as the VT sequences that would draw it again, or as a picture. Christian Parpart proposed it for Contour in January 2021, in issue #161, which is still open. A pull request, also open, implements it with a specification that changes the reply considerably; it is described below.
The request, as proposed
OSC 533 ; top ; left ; bottom ; right ; format ST
The four numbers name the region. Without them the request is for the whole main page, and any of them left out takes whatever value keeps to that, so an omitted bottom is the last row. The issue does not say whether rows and columns count from zero or one. format defaults to PNG, and the issue lists what should be supported without giving them numbers: plain text, VT sequences, sixel, PNG, and raw RGB or RGBA.
The reply, as proposed
OSC 533 ; top ; left ; lines ; columns ; format ; Pt ST
Pt is the screenshot, and the other fields echo the request with every default filled in. The region comes back as a height and width, lines and columns, rather than the bottom and right edges it was asked for with. The issue says nothing about how the data is encoded.
Security
Reading the screen hands whatever is on it to the program that asked, so the issue suggests a per-profile setting, allow, deny or ask, with ask the default, and a dialog that can preview the image before it is handed over. It also suggests a command, contour screenshot, that would take a screenshot and save it to a file or the clipboard.
The revision in pull request 2088
The specification in the pull request, as it stood at commit 11a819c, keeps the number and the idea and settles what the issue left open. It names two problems with the reply as first proposed. It is an OSC 533 like the request, so a reply recorded by script(1) or a log and later played back to a terminal would read as a new request. And its screen content is unescaped: the VT-sequence format contains ESC by construction, so an ST inside it ends the reply early and hands the rest to the program that asked, as though it were input.
The request gains an identifier at the front, and every field may be left empty:
OSC 533 ; Pid ; Pt ; Pl ; Pb ; Pr ; Pf ST
| Parameter | Meaning | Default |
|---|---|---|
Pid | An opaque request identifier, echoed in every reply | 0 |
Pt | Top row | 1 |
Pl | Left column | 1 |
Pb | Bottom row | the last row |
Pr | Right column | the last column |
Pf | Format | 0 |
The coordinates count from one and are inclusive on all four edges, as DECRQCRA and DEC’s other rectangular-area functions count them; zero means the default, and a coordinate beyond the page is taken as its edge. Unlike those, the region is measured from the top left of the page and not from the origin, so DECOM does not move it. Only the main page of the current buffer can be read, not the scrollback. A bare OSC 533 ST therefore asks for the whole page as plain text, where the issue’s default was PNG.
Pf | Format |
|---|---|
0 | Plain text: UTF-8, each row ended by LF, blank cells as spaces |
1 | VT sequences: the same text with the SGR sequences for its colors, each row ended by CRLF |
2 | Sixel: a complete sixel DCS … ST of the region as rendered |
3 | PNG: a whole PNG file of the region as rendered |
Raw RGBA is left out: a page-sized region would be close to a megabyte. A number not in the table is answered as an unsupported format. The two picture formats are a crop of a frame the terminal actually drew, so they include the cursor, any selection, and the scrollback position if the user has scrolled, and the answer to them comes a frame or two after the request. Sixel has no alpha channel and states colors in percentages, so it can be one step off in a channel and leaves a mostly transparent pixel unpainted.
The reply is a privacy message, not an OSC, so it cannot be mistaken for a request:
PM 533 ; Pid ; Ps ; Pt ; Pl ; Pb ; Pr ; Pf ; Pw ; Ph ; data ST (Ps = 1)
PM 533 ; Pid ; Ps ST (otherwise)
The region is echoed as it was resolved, in the request’s own terms of edges, not as a height and width. Pw and Ph are the image’s size in pixels, 0 for the text formats, there so a reader can size a buffer before decoding anything. The data is base64, split into chunks of 4095 bytes before encoding, a multiple of three so that only the last chunk is padded; each chunk is a message of its own with the same header, and a message with Ps 0 always ends the screenshot, even an empty one.
Ps | Meaning |
|---|---|
0 | End of the screenshot |
1 | A chunk of data |
2 | Denied, by the user or by configuration |
3 | The request could not be parsed |
4 | Not a format the protocol has |
5 | The region is inverted and names no cell |
6 | A format this session cannot produce now, such as a picture with no renderer attached |
Every request is answered, a refusal included, so a program that writes one and waits for a read is never left waiting, even while a dialog asks the user. For example, the first five rows and twenty columns as VT sequences, as request 42:
ESC ] 533 ; 42 ; 1 ; 1 ; 5 ; 20 ; 1 ESC \
ESC ^ 533 ; 42 ; 1 ; 1 ; 1 ; 5 ; 20 ; 1 ; 0 ; 0 ; data ESC \
ESC ^ 533 ; 42 ; 0 ESC \
without the spaces, which are there only to make it readable.
The ask default and the per-profile setting are kept. The revision notes that no registry assigns OSC numbers, and that it found no terminal using 533.