├── .editorconfig
├── .github
└── workflows
│ ├── build.yml
│ └── release.yml
├── .gitignore
├── Changelog.md
├── Makefile
├── README.md
└── spec
└── vt-good-image-protocol.tex
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*.tex]
4 | indent_style = space
5 | indent_size = 4
6 | insert_final_newline = true
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 |
11 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches:
6 | - wip
7 | - master
8 | - preview
9 | - release
10 | pull_request:
11 | branches:
12 | - master
13 |
14 | jobs:
15 | compile_pdf:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v1
19 | - name: "install dependencies"
20 | run: |
21 | set -ex
22 | sudo apt -q update
23 | sudo apt install -y texlive-latex-base texlive-latex-extra latexmk
24 | - name: "Compile PDF"
25 | run: |
26 | set -ex
27 | cd spec
28 | latexmk -pdflatex vt-good-image-protocol
29 | - name: "Uploading PDF"
30 | uses: actions/upload-artifact@v2
31 | with:
32 | name: spec
33 | path: spec/vt-good-image-protocol.pdf
34 | if-no-files-found: error
35 |
36 | compile_md:
37 | runs-on: ubuntu-latest
38 | steps:
39 | - uses: actions/checkout@v1
40 | - name: "install dependencies"
41 | run: |
42 | set -ex
43 | sudo apt -q update
44 | sudo apt install -y pandoc
45 | - name: "Compile markdown"
46 | run: |
47 | set -ex
48 | cd spec
49 | pandoc -s vt-good-image-protocol.tex -o vt-good-image-protocol.md
50 | - name: "Uploading markdown"
51 | uses: actions/upload-artifact@v2
52 | with:
53 | name: spec
54 | path: spec/vt-good-image-protocol.md
55 | if-no-files-found: error
56 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | branches:
6 | - preview
7 | - release
8 |
9 | jobs:
10 | compile_pdf:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v1
14 | - name: "install dependencies"
15 | run: |
16 | set -ex
17 | sudo apt -q update
18 | sudo apt install -y texlive-latex-base texlive-latex-extra latexmk
19 | - name: "Compile PDF"
20 | run: |
21 | set -ex
22 | cd spec
23 | latexmk -pdflatex vt-good-image-protocol
24 | - name: "Uploading PDF"
25 | uses: actions/upload-artifact@v2
26 | with:
27 | name: spec
28 | path: spec/vt-good-image-protocol.pdf
29 | if-no-files-found: error
30 |
31 | compile_md:
32 | runs-on: ubuntu-latest
33 | steps:
34 | - uses: actions/checkout@v1
35 | - name: "install dependencies"
36 | run: |
37 | set -ex
38 | sudo apt -q update
39 | sudo apt install -y pandoc
40 | - name: "Compile markdown"
41 | run: |
42 | set -ex
43 | cd spec
44 | pandoc -s vt-good-image-protocol.tex -o vt-good-image-protocol.md
45 | - name: "Uploading markdown"
46 | uses: actions/upload-artifact@v2
47 | with:
48 | name: spec
49 | path: spec/vt-good-image-protocol.md
50 | if-no-files-found: error
51 |
52 | do_release:
53 | name: Create Github release
54 | runs-on: ubuntu-latest
55 | needs: [compile_pdf, compile_md]
56 | steps:
57 | - uses: actions/checkout@v1
58 | # -------------------------------------------------------------
59 | - name: fetch release artifacts
60 | uses: actions/download-artifact@v2
61 | with:
62 | name: spec
63 | # -------------------------------------------------------------
64 | - name: Set Output Variables
65 | id: set_env_var
66 | env:
67 | REPOSITORY: ${{ github.event.repository.name }}
68 | run: |
69 | VERSION=$(grep '^### ' Changelog.md | head -n1 | awk '{print $2}')
70 | SUFFIX=$(grep '^### ' Changelog.md | head -n1 | awk '{print $3}' | tr -d '()')
71 | if [ $REPOSITORY = "master" ]; then IS_PRE='false'; else IS_PRE='true'; fi
72 | if [ $REPOSITORY = "master" ]; then SUFFIX='' ; else SUFFIX='prerelease'; fi
73 | if [ $REPOSITORY != "master" ]; then
74 | TAG_SUFFIX="_prerelease_${GITHUB_RUN_NUMBER}"
75 | else
76 | TAG_SUFFIX=""
77 | fi
78 | RELEASEBODY=$(awk -v RS='^### ' '/^'$VERSION'/ {print $0}' Changelog.md | tail -n+3)
79 | RELEASEBODY="${RELEASEBODY//'%'/'%25'}"
80 | RELEASEBODY="${RELEASEBODY//$'\n'/'%0A'}"
81 | RELEASEBODY="${RELEASEBODY//$'\r'/'%0D'}"
82 | echo "::set-output name=version::${VERSION}"
83 | echo "::set-output name=tag_suffix::${TAG_SUFFIX}"
84 | echo "::set-output name=RUN_ID::${GITHUB_RUN_NUMBER}"
85 | echo "::set-output name=IS_PRERELEASE::${IS_PRE}"
86 | echo "::set-output name=RELEASENAME_SUFFIX::${SUFFIX}"
87 | echo "::set-output name=RELEASEBODY::${RELEASEBODY}"
88 | # -------------------------------------------------------------
89 | - name: Create Github release page
90 | id: create_release
91 | uses: actions/create-release@v1
92 | env:
93 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
94 | with:
95 | tag_name: v${{ steps.set_env_var.outputs.version }}${{ steps.set_env_var.outputs.tag_suffix}}
96 | release_name: Terminal Good Image Protocol ${{ steps.set_env_var.outputs.version }}-${{ steps.set_env_var.outputs.RUN_ID }} ${{ steps.set_env_var.outputs.RELEASENAME_SUFFIX}}
97 | body: |
98 | ${{ steps.set_env_var.outputs.RELEASEBODY }}
99 | draft: true
100 | prerelease: ${{ steps.set_env_var.outputs.IS_PRERELEASE }}
101 | # -------------------------------------------------------------
102 | - name: Upload PDF
103 | id: upload-release-pdf
104 | uses: actions/upload-release-asset@v1
105 | env:
106 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
107 | with:
108 | upload_url: ${{ steps.create_release.outputs.upload_url }}
109 | asset_path: vt-good-image-protocol.pdf
110 | asset_name: vt-good-image-protocol-${{ steps.set_env_var.outputs.version }}-${{ steps.set_env_var.outputs.RUN_ID }}.pdf
111 | asset_content_type: application/pdf
112 | # -------------------------------------------------------------
113 | - name: Upload markdown
114 | id: upload-release-md
115 | uses: actions/upload-release-asset@v1
116 | env:
117 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
118 | with:
119 | upload_url: ${{ steps.create_release.outputs.upload_url }}
120 | asset_path: vt-good-image-protocol.md
121 | asset_name: vt-good-image-protocol-${{ steps.set_env_var.outputs.version }}-${{ steps.set_env_var.outputs.RUN_ID }}.md
122 | asset_content_type: text/markdown
123 |
124 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.tmp
2 | *.aux
3 | *.log
4 | *.toc
5 | *.pdf
6 | *.out
7 | *.fls
8 | *.fdb_latexmk
9 | *.synctex.gz
10 | .fake
11 | .ionide
12 | /out
13 |
--------------------------------------------------------------------------------
/Changelog.md:
--------------------------------------------------------------------------------
1 | ### 0.1.0 (unreleased)
2 |
3 | - initial draft
4 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # vim:noet
2 |
3 | BASENAME = vt-good-image-protocol
4 | SOURCE_FILES = spec/$(BASENAME).tex
5 | TARGET_DIR = out
6 |
7 | all: ${TARGET_DIR}/${BASENAME}.pdf
8 |
9 | clean:
10 | @rm -vf ${TARGET_DIR}/*
11 |
12 | ${TARGET_DIR}/${BASENAME}.pdf: $(SOURCE_FILES)
13 | @mkdir -p ${TARGET_DIR}
14 | @pdflatex -aux_directory=${TARGET_DIR} -output-directory=${TARGET_DIR} $^
15 | @pdflatex -aux_directory=${TARGET_DIR} -output-directory=${TARGET_DIR} $^
16 |
17 | .PHONY: all clean
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Terminal \*Good\* Image Protocol
2 |
3 | **IMPORTANT: THIS PROJECT IS IN ALPHA STAGE & ACTIVE DEVELOPMENT**
4 |
5 | This repository aims to finish and formalize the `*Good* Image Protocol` that
6 | was posted on terminal-wg issue [#26](https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/26).
7 |
8 | ## Goal of this repository
9 |
10 | I want to finally formalize what other people have been already put great work in (see references),
11 | and also come up with a reference implementation (for verifying the spec and as a technical preview).
12 |
13 | It would be nice if this repository serves as a communication hub for improving this spec
14 | that ideally enough terminal emulators will adopt so we could call this the future defacto image protocol
15 | for terminals, so that developers have it easier in the future on how to get images into their
16 | terminal applications.
17 |
18 | ## Roadmap
19 |
20 | - [x] get the actual non-subjective content extracted out of the other sources into this one specification draft.
21 | - [x] create CI job for auto-generating PDF/markdown of the latest draft to be downloadable
22 | - [x] create CI job for providing prereleases of the draft specification.
23 | - [ ] Move Changelog into .tex file and let CI's release.yml extract it from there
24 | - [ ] Create Github pages that have an auto-generated PDF/markdown version of this specification.
25 | - [ ] Hopefully get enough terminal and TUI app devs attracted to collaborate in a positive, friendly, and productive manner.
26 | - [ ] CLI tool for `cat`ing images onto the screen (a shell script should be sufficient).
27 | - [ ] CLI tool for testing the feature availability (could be integrated in the above tool with a `--test` flag)
28 |
29 | ## FAQ
30 |
31 | - **Why LaTeX and not Markdown?** Expressivity and the fact that you can convert to Markdown: https://pandoc.org/demos.html
32 | - **Why GitHub and not GitLab on freedesktop?** Better reachability.
33 |
34 |
--------------------------------------------------------------------------------
/spec/vt-good-image-protocol.tex:
--------------------------------------------------------------------------------
1 | % vim:cc=80:cole=0
2 | \documentclass[a4paper]{article}
3 | %\documentclass[a4paper, 20pt]{extreport}
4 | \usepackage[utf8]{inputenc}
5 | \usepackage[english]{babel}
6 |
7 | \usepackage{colortbl}
8 | \usepackage{todonotes}
9 |
10 | \usepackage[hidelinks]{hyperref}
11 | \hypersetup{
12 | colorlinks=true,
13 | linkcolor=blue,
14 | filecolor=magenta,
15 | urlcolor=cyan
16 | }
17 |
18 | % \usepackage{fancyhdr}
19 | % \usepackage{graphicx}
20 |
21 | \usepackage{draftwatermark}
22 | \SetWatermarkText{Draft}
23 | \SetWatermarkScale{4}
24 |
25 | \usepackage[english]{babel}
26 |
27 | \usepackage{xcolor}
28 | \definecolor{light-gray}{gray}{0.95}
29 |
30 | \usepackage{geometry}
31 | \geometry{legalpaper, margin=1in}
32 |
33 | \title{VT Good Image Protocol \\
34 | a standardization proposal}
35 | \author{Christian Parpart}
36 | % \date{2020-12-18 (draft, revision 0)}
37 | \date{\today \quad (draft, revision 0)}
38 |
39 | \newcommand{\code}[1]{\colorbox{light-gray}{\texttt{#1}}}
40 |
41 | \newcommand{\DA}{\code{DA1}}
42 | \newcommand{\DECRQM}[1]{\code{CSI ? #1 \$ p}}
43 | \newcommand{\DECRST}[1]{\code{CSI ? #1 l}}
44 | \newcommand{\DECSET}[1]{\code{CSI ? #1 h}}
45 |
46 | \newcommand{\GoodImageProtocol}{\code{Good Image Protocol}}
47 |
48 | \begin{document}
49 |
50 | \maketitle
51 |
52 | \tableofcontents
53 |
54 | %\newpage
55 |
56 | \section{Motivation} % {{{
57 |
58 | For many decades Sixel and ReGIS have been the only image protocols for terminal emulators.
59 | While both are ancient and not even widely implemented, now people are used
60 | to seeing images and even emoji everywhere.
61 | Those people may eventually touch a virtual terminal emulator and expect it to be no different
62 | than what they are used to from other software systems.
63 |
64 | There is a growing interest in displaying images in todays
65 | virtual terminal emulators.
66 |
67 | Since these protocols are were not designed with todays needs in mind,
68 | virtual terminal emulator developers have started implementing their own
69 | proprietary protocols for displaying images as Sixel and related
70 | protocols were simply not fullfulling today's needs anymore.
71 |
72 | While recent efforts to image protocols are positive, it also leads to fragmentation in the ecosystem
73 | because application developers do not know what to support in case they intend
74 | to display images in their client applications, and even new terminal emulator
75 | developers don't know what protocol to implement.
76 |
77 | There is also a recent resurrection of the Sixel bitmap protocol
78 | to be implemented by some terminal emulator
79 | \footnote{Alacritty, Contour, gnome-terminal, iTerm2, wezterm, xterm.js}
80 | and library \footnote{notcurses, libsixel} developers,
81 | however, none of them is 100\% conforming to how Sixel used to work 50 years ago,
82 | as there is no easy way to access the hardware they were implemented on
83 | and also xterm does not implement every aspect of Sixel while existing
84 | documentation on sixel is also leaving too much room for varying interpretation.
85 |
86 | This specification attempts to unify all those image protocols and addresses
87 | some of the issues, not as a superset, but rather as a largest common denominator,
88 | with usability, simplicity, and implementation adaptability in mind and
89 | is also an attempt to formalize what was written down in \ref{ref:twg-gip},
90 | which can be seen as a conclusion of many discussions that happened scattered
91 | across different forums on the topic of a future image protocol.
92 |
93 | % }}}
94 | \section{Terminology} % {{{
95 | \begin{itemize}
96 | \item \textbf{screen cell}; a rectanglular area of the screen that can contain a character with
97 | its graphics rendition or an image fragment
98 | \item \textbf{image fragment}; a rectanglular tile of an image that perfectly fits into a screen cell
99 | \item \textbf{image storage pool}; a backing store for images received for future operations
100 | \end{itemize}
101 |
102 | \todo{more terminology to add?}
103 |
104 | % }}}
105 | \section{Prior art and current state} % {{{
106 |
107 | Prior art of image protocols for terminals are as follows:
108 |
109 | \subsection{Tektronix}
110 |
111 | \begin{itemize}
112 | \item First appeared in 1970s
113 | \item Tektronix 4010 series was a family of text-and-graphics computer terminals based on storage-tube technology created by Tektronix.
114 | \item implemented by: xterm
115 | \end{itemize}
116 |
117 | \subsection{DEC ReGIS graphics}
118 |
119 | \begin{itemize}
120 | \item First appeared in VT125, in July 1981
121 | \item vector graphics based
122 | \item implemented by: xterm
123 | \end{itemize}
124 |
125 | \subsection{Sixel graphics}
126 |
127 | \begin{itemize}
128 | \item Sixel grpahics first appeared in LA50 dot-matrix printers (1983) and short after in the VT240 in October 1983.
129 | \item It is pixel based and positions the graphics cursor in a way it is most optimal for dot printers,
130 | that could print 6 pixels in height per line.
131 | \item Specialized image format optimized for 6-pin printers.
132 | \item Supports scrolling the screen if the image does not fit the current screen.
133 | \item Supports passing different aspect ratio. This is rarely implemented by virtual terminal emulators though.
134 | \item Supports endless vertical rendering, e.g. to print seismograph data (rarely implemented by virtual terminal emulators).
135 | \item Implemented by: xterm, mlterm, contour, wezterm, vte, possibly others.
136 | \end{itemize}
137 |
138 | This protocol only understands pixels and thus is dependant on the
139 | configured font size and screen resolution of the terminal, which
140 | terminal emulators seem to have solved differently and therefore cannot
141 | be relied on.
142 |
143 | \subsection{Terminology image protocol}
144 |
145 | Terminology's image protocol is rather a media transport protocol as it
146 | can also be used to render animations, including videos.
147 |
148 | \begin{itemize}
149 | \item First appeared in june, 2012.
150 | \item Uses vt sequences inspired by xterm's sequence extensions.
151 | \item Specification is in the source code repository's \texttt{readme.md} file.
152 | \item Implemented by: terminology
153 | \end{itemize}
154 |
155 | \subsection{iTerm2 image protocol}
156 |
157 | \begin{itemize}
158 | \item First introduced in 2014 with documentation added in 2015.
159 | \item Can associate a file name (Base64 encoded) to the rendered image.
160 | \item Image display size can be pixel based as well as cell based.
161 | \item Also has the ability to address the width and height relative to the terminal window size.
162 | \item Image data is Base64 encoded.
163 | \item Any image format that macOS supports is supported by iTerm2's image protocol,
164 | including PDF, PICT, EPS, or any number of bitmap data formats (PNG, GIF, etc.).
165 | \item implemented by: iterm, wezterm (partly)
166 | \end{itemize}
167 |
168 | The dependency on macOS for supported image formats makes it a little blurry
169 | specification also.
170 |
171 | \subsection{DomTerm's inline image support}
172 |
173 | \begin{itemize}
174 | \item Domterm's image support appeared in 2016.
175 | \item No explicit image protocol but a "insert html"-protocol that does support images.
176 | \item Specification is in the source code repository's \texttt{readme.md} file.
177 | \item Implemented by: DomTerm
178 | \end{itemize}
179 |
180 | The typical way to insert an image is to insert an HTML \texttt{
} element,
181 | with the src attribute using a data: URL scheme,
182 | with the actual data inline as base64.
183 |
184 | Any image format supported by the underlying browser engine is allowed.
185 |
186 | The \texttt{
} element can contain attributes such as width, height, alt
187 | and options to add scrollbars.
188 |
189 | The tight integration to the browser makes it hard to be adopted by native
190 | terminals.
191 |
192 | \subsection{Kitty image protocol}
193 |
194 | \begin{itemize}
195 | \item First appeared in 2017
196 | \item Seperates image upload from image display
197 | \item Can mandate image sizes in pixels as well as in screen cell dimensions.
198 | \item Images are rendered independantly of text with a specified Z-axis.
199 | \item Images can be deleted without knowning their names but only by specifying X/Y/Z axis
200 | and delete all images intersecting these criteria.
201 | \item Image formats supported are: RGB, RGBA, PNG.
202 | \item Image data is Base64 encoded.
203 | \item Supports optionally compressing the image data.
204 | \item Supports various image data transmission methods:
205 | \begin{itemize}
206 | \item inline, as part of the VT sequence
207 | \item named shared memory
208 | \item path to local files
209 | \end{itemize}
210 | \item Optionally deletes the local file when requested and the file path is in a secure location.
211 | \item Hard coded image storage pool to 320 MB (per screen buffer).
212 | \item implemented by: kitty, wezterm (partly)
213 | \end{itemize}
214 |
215 | None of the above image protocols are a good candiate. iTerm2's image protocol is very simple and
216 | can be rendered by specifying screen cell sizes instead of relying on pixels, but lacks some
217 | flexibility.
218 |
219 | Kitty image protocol on the other hand does provide very good flexibility but is way too complex which
220 | would hinder broader adoptability and conforming implementations, potentially leading to partial
221 | implementations and thus fragmentation.
222 | There is also an added complexity (such as support for Z-axis) and the ability
223 | to send images in a way that does not work trivially when the terminal is
224 | connected to remote clients (such as via SSH). This all seems to hinder
225 | adopting a otherwise very flexible image protocol.
226 |
227 | The \GoodImageProtocol specification aims to be future proof with regards to
228 | the young generation of terminal users, as well as being simple enough
229 | to be widely accepted and adopted on the terminal side as well as client side,
230 | yet allowing future extensions to this protocol
231 | without breaking compatibility to existing implementations.
232 |
233 | % }}}
234 | \section{Requirements} % {{{
235 |
236 | This section lays down the principles and requirements of \GoodImageProtocol.
237 |
238 | \begin{enumerate}
239 | \item \textbf{feature detectability} - the image protocol must be easily detectable with well known techniques.
240 | \item \textbf{protocol forward-compatibility} - the protocol must be easily extendable in input
241 | parameters as well as reusability of the image storage pool
242 | (such as icon-display, desktop-notifications, background images).
243 | \item \textbf{multiplexer-aware} - multiplexers must be able to fully operate without analyzing the image format.
244 | it must be possible to blindingly forward the image data to the outputting terminals.
245 | \item \textbf{deterministic emulation} - the image rendering must not be affected by font size
246 | or similar properties nor on external api to make productive use of this protocol.
247 | \item \textbf{synchronous operations by default} - no asynchronous operations unless explicitly requested.
248 | \item \textbf{preserve aspect ratio by default}
249 | \item \textbf{remote-terminal capable} - no dependency on the local host, such as the local file system.
250 | \item \textbf{upload and render seperation} - image upload must be decoupled from image display
251 | \item \textbf{support for rendering tiles of an image} - adding the ability to only render tiles
252 | of an image greatly assists client applications when only rendering parts of an image is
253 | needed (such as in multiplexers).
254 | \end{enumerate}
255 |
256 | \paragraph*{}
257 |
258 | The document at [\ref{ref:twg-gip}] suggests cell based masking for rendering to help rendering more
259 | complex scenes such as in windowed TUI applications or terminal multiplexers with overlaying contents.
260 | However, the same can be achieved with a sequence of Image-Render commands specifying a
261 | sub-rectangle (tiles) to be rendered of the referenced image.
262 |
263 | % }}}
264 | \section{Backwards Compatibility} % {{{
265 |
266 | Since all other image protocols are pixel based, the proposed image protocol does not
267 | attempt to retain any backwards compatibility. Instead, the goal is to create
268 | an image protocol that is future proof with todays needs in mind.
269 |
270 | % }}}
271 | \section{Future Compatibility and Stability} % {{{
272 |
273 | In order to leave room for improvements, the VT sequences should be designed in a way
274 | that allows specifying additional parameters in the future, and simultaneously ensures
275 | that older implementations can still work while safely ignoring any new parameters.
276 |
277 | % }}}
278 | \section{Terminal Emulator Requirements} % {{{
279 |
280 | This is the list of resource requirements that must be guaranteed
281 | by the virtual terminal emulator.
282 |
283 | \begin{enumerate}
284 | \item at least 64 images concurrently
285 | \item at least 4 MB per image uncompressed (RGBA8888)
286 | \end{enumerate}
287 |
288 | Upper limits must be present for security reasons but can be varying by implementation.
289 |
290 | % }}}
291 | \section{Performance Considerations} % {{{
292 |
293 | \todo{performance considerations on the backend side as well as rendering}
294 |
295 | tbd.
296 |
297 | % }}}
298 | \section{Security Considerations} % {{{
299 |
300 | \begin{itemize}
301 | \item image upload spamming - should be avoidable by a meaningful limit
302 | on how many images can be uploaded at the same time.
303 | Exceeding the limit will result in evicting ideally older images,
304 | leading to dangling image fragments, as their related image has been
305 | evicted. A placeholder or an empty screen cell may be displayed instead or no image at all.
306 | \item huge image uploads - must be avoidable by limiting the number
307 | of pixels an image can take.
308 | \item invalid image uploads - a terminal proxy (such as tmux) do not
309 | implicitly need to validate image formats as they are usually just
310 | forwarding the blobs to the connected terminal. A non-proxying
311 | terminal however will validate implicitly by loading the specified
312 | file format.
313 | \item invalid image render requests (such as out of bounds in offsetted-renders) -
314 | invalid named images will not be displayed.
315 | Overextending dimensions will be displayed but result in cut-of images.
316 | \end{itemize}
317 |
318 | % }}}
319 | \section{Semantics} % {{{
320 | \subsection{The lifecycle of an image} % {{{
321 |
322 | While classically it should be allowed to just display images,
323 | with having the cursor moved, and forget about that one has rendered that
324 | image, it must also be possible to render the same image multiple times
325 | in an resource efficient time.
326 |
327 | Therefore, the concept of image display is broken up into multiple parts,
328 | by separating the image upload from rendering, so
329 | that the same image data can be reused in multiple render commands with
330 | the choice of either drawing the full image or just parts of it.
331 | The latter is important for toolkit developers to efficiently redraw
332 | patially overlapping images.
333 |
334 | \subsubsection*{Uploading the image} % {{{
335 |
336 | The command for uploading the image simply uploads the image.
337 | In order to make use of that previously uploaded image, a application-specific
338 | fully qualifying (and ideally unique) name is being passed.
339 | This name can be used in future commands to render, rerender the image
340 | either in its whole or parts of it.
341 |
342 | The link between the name and the uploaded image can be explicitly released,
343 | and then be reused by other image uploads while prior image uploads to that
344 | name are preserved.
345 |
346 | The image upload does not generate any visible output, but may optionally
347 | (not by default) reply to the application a success indication.
348 |
349 | % }}}
350 | \subsubsection*{Rendering the image} % {{{
351 |
352 | Rendering the image is done by referencing the previously uploaded
353 | image by its name and then telling the command where to render it
354 | in screen coordinates, with number of columns and number of lines to fill
355 | with that image. This can be seen similar to the `DECFRA` VT sequence
356 | that also fills a rectangular region with a fixed SGR, except
357 | that this command filles the rectangular area with an image instead.
358 |
359 | % }}}
360 | \subsubsection*{Releasing the image} % {{{
361 |
362 | When the image's referenced name is not needed anymore it must be released.
363 | This does not implicitly erase already rendered screen areas referencing the image.
364 | It purely disassociates the name with the image, eventually leading
365 | to resource eviction when no screen cell is holding a reference to the
366 | uploaded image anymore.
367 |
368 | % }}}
369 | \subsubsection*{Rendering the image only once} % {{{
370 |
371 | While the above is sufficient to efficiently operate with images in the terminal,
372 | there are usecases where an image needs to be rendered exactly once and
373 | seperating upload, render, and release stages is therefore unnecessary,
374 | such as simply putting the image onto the screen and have the cursor moved
375 | accordingly, so that it perfectly fits into the command flow of your primary screen.
376 |
377 | \textbf{iTerm2} is having such a special command, called \code{imgcat},
378 | there is also \code{lsix} to display images in the spirit of \code{ls},
379 | and there are similar tools for kitty's and terminology's protocol, too.
380 |
381 | \GoodImageProtocol must provide a command to make it trivial for application
382 | developers to achieve the same.
383 |
384 | % }}}
385 |
386 | % }}}
387 | \subsection{Feature Detection} % {{{
388 |
389 | \DA is already used to advertise terminal features, including Sixel graphics, and thus,
390 | \DA is also used to advertise \GoodImageProtocol support, for consistency.
391 |
392 | There is some improved feature detection specification work ongoing\todo{reference missing},
393 | so there may be other ways to detect \GoodImageProtocol in the future, when that is ready.
394 |
395 | % }}}
396 | \subsection{Querying Resource Limits} % {{{
397 |
398 | Resource limits must be queryable whilest the requirements must be met.
399 | Every resource requirement also has a limit at exactly
400 | the value of the requirement or above, and must be queryable
401 |
402 | \begin{itemize}
403 | \item number of images displayable concurrently (visible or not visible)
404 | A recommendation for this limit is 128 on terminals running on desktop computers.
405 | \item number of bytes an the image data must not exceed in its respective image format.
406 | \item maximum width and height for images.
407 | \end{itemize}
408 |
409 | % }}}
410 | \subsection{Upload Image} % {{{
411 |
412 | Uploads an image for future render operations.
413 |
414 | \subsubsection*{Parameters}
415 |
416 | \begin{tabular}{|m{3cm}|m{12cm}|}
417 | \hline
418 | \textbf{parameter name} & \textbf{description} \\
419 | \hline
420 | \textbf{name} & a unique identifier for the uploaded image \\
421 | \textbf{format} & a value that determines the image format. \\
422 | & See section \ref{sec:supported-image-formtats} for available image formats \\
423 | \textbf{width} & optional pixel width of the given image
424 | (only required if this information is not provided
425 | inline via the \textbf{data} field) \\
426 | \textbf{height} & optional pixel height of the given image
427 | (only required if this information is not provided
428 | inline via the \textbf{data} field) \\
429 | \textbf{data} & image data in the specified input format \\
430 | \hline
431 | \end{tabular}
432 |
433 | \subsubsection{Idempotency}
434 |
435 | Image upload can be implemented to be idempotent, but doesn't have to,
436 | i.e. the storage pool keeps an internal hash of each image that is
437 | automatically constructed upon image upload.
438 |
439 | If the image was already uploaded, that image's reference count is incremented
440 | and in case it is a named resource, that one will point to that existing one.
441 |
442 | % }}}
443 | \subsection{Render Image} % {{{
444 |
445 | Renders an image that has been previously uploaded.
446 | The image will be rendered with the top-left matching the current ansi cursor position.
447 | The cursor will not be moved by this operation.
448 |
449 | \subsubsection*{Parameters}
450 |
451 | \begin{tabular}{|m{3cm}|m{2cm}|m{10cm}|}
452 | \hline
453 | \textbf{parameter name} & \textbf{default} & \textbf{description} \\
454 | \hline
455 | \textbf{name} & & unique identifier referencing a previously uploaded image \\
456 | \textbf{screen-rows} & & number of screen cells to render horizontally \\
457 | \textbf{screen-cols} & & number of screen cells to render vertically \\
458 | \textbf{screen-layer} & above & render image below text (0), replace text (1), above text (2) \\
459 | \textbf{resize-policy} & noresize & optional, mandates how to resize the image within the screen cells \\
460 | \textbf{alignment-policy} & middlecenter & optional, mandates how to align the image within the screen cells \\
461 | \textbf{image-x-offset} & 0 & start rendering at the given pixel x-offset cell of the image \\
462 | \textbf{image-y-offset} & 0 & start rendering at the given pixel y-offset cell of the image \\
463 | \textbf{image-width} & auto-max & optional, number of pixels of the image's width to display \\
464 | \textbf{image-height} & auto-max & number of pixels of the image's height to display \\
465 | \textbf{update-cursor} & false & optional, tells the terminal to move the text cursor after having the image rendered (image left aligned) below the image \\
466 | \textbf{request-status} & false & request a success/failure status response code from the terminal \\
467 | & & if value is true, a response is sent back to the application \\
468 | & & to indicate success or failure. \\
469 | & & if value is set to false (or parameter is not present), \\
470 | & & no response is sent back to the application. \\
471 | \hline
472 | \end{tabular}
473 |
474 | % \paragraph*{}
475 | % If parameter \textbf{screen-width} and \textbf{screen-height} are both omitted (or set to 0), then the
476 | % number of screen cells will be automatically determined.
477 |
478 | \paragraph*{}
479 | if one of the parameters \textbf{screen-width} and \textbf{screen-height}
480 | is present and the other is missing, the missing one will be automatically
481 | determined by preserving the aspect ratio.
482 |
483 | \paragraph*{}
484 | Rendered images that produce a padding due to alignment- and resize-policy
485 | will fill the gap with the currently active sgr background color.
486 |
487 | \paragraph*{}
488 | Reverse video mode mode (\code{decscnm}) will affect the padding color but not the image.
489 |
490 | \subsubsection*{Resize Policy}
491 |
492 | \begin{tabular}{ |l|l| }
493 | \hline
494 | \textbf{Name} & \textbf{Description} \\
495 | \hline
496 | NoResize & Does not perform any resize, leading to a padding on one or two sides \\
497 | & as mandated by the alignment-policy. \\
498 | ResizeToFit & Resizes the image to fit the specified screen width and height, \\
499 | & leading to a padding on zero or one sides as mandated by the alignment-policy. \\
500 | ResizeToFill & Resizes the image to fill the specified screen width and height, \\
501 | & preserving the aspect ratio, leading to potential clipping depending on the \\
502 | & alignment-policy. \\
503 | StretchToFill & Resizes the image to fill the specified screen width and height, \\
504 | & ignoring the aspect ratio, ignoring alignment-policy. \\
505 | \hline
506 | \end{tabular}
507 |
508 | \subsubsection*{Alignment Policy}
509 |
510 | \begin{tabular}{ |l|l| }
511 | \hline
512 | \textbf{Name} & \textbf{Description} \\
513 | \hline
514 | TopCenter & The image is aligned vertically on the top and horizontally in the center of the screen. \\
515 | TopStart & The image is aligned vertically on the top and horizontally on the left. \\
516 | TopEnd & The image is aligned vertically on the top and horizontally on the right. \\
517 | \hline
518 | MiddleCenter & The image is aligned vertically and horizontally in the center of the screen. \\
519 | MiddleStart & The image is aligned vertically centered and horizontally on the left. \\
520 | MiddleEnd & The image is aligned vertically centered and horizontally on the right. \\
521 | \hline
522 | BottomCenter & The image is aligned vertically on the bottom and horizontally in the center of
523 | the screen. \\
524 | BottomStart & The image is aligned vertically on the bottom and horizontally on the left. \\
525 | BottomEnd & The image is aligned vertically on the bottom and horizontally on the right. \\
526 | \hline
527 | \end{tabular}
528 |
529 | % }}}
530 | \subsection{Upload and Render Image} % {{{
531 |
532 | This uploads and renders the image via a single VT sequence. Therefore no image Id
533 | is required and there won't be any way to reference that image after either.
534 |
535 | The parameters of this function is the sum of the image upload and image render parameters excluding the unique
536 | identifier and excluding sub-rectangle rendering parameters.
537 |
538 | The image will be rendered with the top-left matching the current ANSI cursor position.
539 | The cursor will not be moved by this operation.
540 |
541 | \subsubsection*{Parameters}
542 |
543 | \begin{tabular}{|m{3cm}|m{2cm}|m{11cm}|}
544 | \hline
545 | \textbf{parameter name} & \textbf{default} & \textbf{description} \\
546 | \hline
547 | \textbf{screen-rows} & & number of screen cells to render horizontally \\
548 | \textbf{screen-cols} & & number of screen cells to render vertically \\
549 | \textbf{resize-policy} & noresize & optional, mandates how to resize the image within the screen cells \\
550 | \textbf{alignment-policy} & middlecenter & optional, mandates how to align the image within the screen cells \\
551 | \textbf{image-x-offset} & 0 & start rendering at the given pixel x-offset cell of the image \\
552 | \textbf{image-y-offset} & 0 & start rendering at the given pixel y-offset cell of the image \\
553 | \textbf{image-format} & & a value that determines the image format. \\
554 | & & see section \ref{sec:supported-image-formtats} for available image formats \\
555 | \textbf{image-width} & auto-max & optional, number of pixels of the image's width to display \\
556 | \textbf{image-height} & auto-max & number of pixels of the image's height to display \\
557 | \textbf{image-data} & & image data in the specified input format \\
558 | \textbf{update-cursor} & false & optional, tells the terminal to move the text cursor after having the image rendered (image left aligned) below the image \\
559 | \textbf{auto-scroll} & & boolean, indicating whether or not the page is beign scrolled up \\
560 | & & if the image would not fit otherwise \\
561 | \hline
562 | \end{tabular}
563 |
564 | \todo{specify how auto-scroll can be achieved in primary screen for render and upload-and-render actions.}
565 |
566 | \paragraph{*}
567 | in primary screen, if rendering the image would render below the main page area,
568 | the screen is scrolled up accordingly to ensure the bottom of the image can still be seen.
569 | this may cause the top of the image to be moved into the scrollback area
570 | if the image to be rendered is larger than the main page's line count.
571 |
572 | % }}}
573 | \subsection{Release Image} % {{{
574 |
575 | Removes the mapping of the name to the image in a storage pool.
576 | This will cause decrementing the use-count of the previously uploaded image.
577 | Existing rendered images are not affected by this operation.
578 |
579 | \subsubsection*{parameters}
580 |
581 | \begin{tabular}{|l|l|l|}
582 | \hline
583 | \textbf{parameter name} & \textbf{default} & \textbf{description} \\
584 | \hline
585 | \textbf{name} & & the unique identifier of the uploaded image. \\
586 | \hline
587 | \end{tabular}
588 |
589 | % }}}
590 | \subsection{Storage Management} % {{{
591 |
592 | Uploaded images are reference counted.
593 | Uploading a named image will associate the uploaded image with the specified
594 | name and initialize the image's reference count to 1.
595 |
596 | When uploading an image would exceed the storage pool limits,
597 | the host may choose to actively evict images.
598 |
599 | The recommendation here is to use FIFO for eviction,
600 | but this is not a mandatory algorithm.
601 | If a terminal author comes with a much smarter eviction policy implementation,
602 | that should not in FIFO-order until the new image fits.
603 |
604 | If the image is larger than the allowed storage size, the upload will fail.
605 |
606 | Evicted images that were still held in screen cells will
607 | either display a image placeholder or an empty screen cell, neither
608 | is mandatory and free to chose by the terminal author.
609 |
610 | Displaying an image results in incrementing the reference counter
611 | by the number of screen cells that are holding fragments of the image.
612 |
613 | Clearing a screen cell holding an image fragment (e.g. by overwriting
614 | or deleting its contents) will decrement the image reference count of
615 | the prior referenced image.
616 |
617 | When no screen cell is holding a reference to the image,
618 | the corresponding reference counter should be either 1 (if uploaded in a separate step)
619 | or 0 (if uploaded within the render instruction).
620 |
621 | When the reference count gets down to zero, the image can be safely evicted.
622 |
623 | Releasing the image by its name will remove the name-to-image association, and thus,
624 | decrement its reference counter.
625 |
626 | Uploading a new image with an already used name will first release the old name-to-image association
627 | as mentioned earlier and then register the new image with its name. This will not cause
628 | any visible side effects - existing image fragments to the old image will not be touched.
629 |
630 | % }}}
631 | \subsection{Interoperability with other VT sequences} % {{{
632 |
633 | The rendered image can either replace any existing text on the rendered
634 | screen cells, render below or render above of the screen's text.
635 |
636 | To retain interop with all existing screen buffer mutating sequences,
637 | any image fragments being associated to a screen cell are strongly bound
638 | to that cell, e.g. when this cell is being moved to the right, the associated
639 | image fragemnt will move to the right, too.
640 |
641 | VT sequences that are designed to delete text, will also delete any
642 | associated image fragment data in this screen cell as well.
643 |
644 | \subsubsection*{Cursor and margin}
645 |
646 | The cursor position respects
647 | \code{DECOM}\footnote{https://www.vt100.net/docs/vt510-rm/DECOM.html}
648 | margin and an image must not leave the current horizontal nor vertical margins
649 | when being rendered.
650 | The image gets clipped if it would render outside the margin.
651 |
652 | \subsubsection*{Screen modifying commands}
653 |
654 | All existing screen modifying VT sequences preserve their meanings.
655 | That is, commands such as
656 | \code{DECIC}\footnote{https://www.vt100.net/docs/vt510-rm/DECIC.html},
657 | and others will split the image in two halfs.
658 |
659 | \subsubsection*{Screen cell characters and image tiles}
660 |
661 | Image fragments can be rendered above text, below text, or replace text.
662 |
663 | Analogous, when an image is placed into a screen cell that currently holds
664 | an image fragement that is meeant to replace text,
665 | that text will replace the image fragment as well.
666 |
667 | \subsubsection*{Image alpha channel and graphics rendition background color}
668 |
669 | Images with an alpha channel will blend into the graphics renditions
670 | background color (respecting reverse-video attribute) of that cell analogous
671 | to how padding pixel color is applied for image fragments.
672 |
673 | \subsubsection*{Hyperlinks}
674 |
675 | If the terminal emulator supports hyperlinks and the application has initiated
676 | a hyperlink, followed by rendering an image, the whole rendered image becomes
677 | hyperlinked, analogous to how hyperlinks are applied to text.
678 |
679 | \subsubsection*{Text reflow}
680 |
681 | Text reflow is supported only inconsistently across a few terminals.
682 | Therefore this specification does not attempt to address this for images.
683 | Image cells behave just like text cells, potentially wrapping on shrink
684 | and eventually merging back when regrown.
685 |
686 | When text reflow is going to be formally specified it must then also address images.
687 |
688 | \subsubsection*{Clearing the screen}
689 |
690 | VT sequences (such as \code{CSI Ps J}) that reset at least the textual contents
691 | of the screen cells will also clear their image fragment referencing an underlying image,
692 | possibly also releasing the underlying image(s) from the image storage pool
693 | when their reference count has reached zero.
694 |
695 | \subsubsection*{Primary and alternate screen}
696 |
697 | Alternate screen and primary screen maintain both a shared image storage pool.
698 |
699 | % }}}
700 |
701 | % }}}
702 | \section{Syntax} % {{{
703 |
704 | This section maps each semantic action to actual VT sequences.
705 |
706 | Each command is using the \code{OSC} protocol with an embedded message as
707 | described below.
708 |
709 | In order to stay consistent to already existing \code{OSC}'s,
710 | the image commands below also reserve a numeric identifier the uniquely
711 | identify the message.
712 |
713 | The basic format is as follows:
714 |
715 | \code{OSC 314 ; ST}
716 |
717 | \todo{Unfinished text...}
718 |
719 | \subsection{Message Format} % {{{
720 |
721 | This message format helps sending arbitrary parametrized messages
722 | as payload and is suitable for \code{DCS} and \code{OSC} payloads.
723 |
724 | The message format is inspired by and trivialized as basic HTTP message like
725 | format with the following basic rules:
726 |
727 | \begin{itemize}
728 | \item A message is devided into two optional parts, i.e. a set of headers and the body part.
729 | \item Headers and body are seperated by \code{;}.
730 | \item Header entries are seperated by \code{,}.
731 | \item Header name and value is seperated by \code{=}.
732 | \item Duplicate header names will override the previousely declared ones.
733 | \item Header value and message body can be optionally Base64 encoded by prepending \\
734 | an exclamation mark (\code{!}) at the beginning of the header's value or body.
735 | \item superfluous commas in header seperation are ignored
736 | \item header names without a value reflect a boolean truth value,
737 | its \code{=} can therefore be omitted.
738 | \end{itemize}
739 |
740 | When this message format is used as payload for \code{OSC} commands, then
741 | the \code{OSC}'s payload will still need to contain the leading numeric
742 | number followed by a semicolon (\code{;}) in order to retain consistency
743 | with existing \code{OSC} implementations.
744 |
745 | \subsubsection*{Resource Requirements}
746 |
747 | These are the requirements a message parser must be able to process at least.
748 | There should always be a limit, too, which is implicitly at least as big as
749 | the here specified requirements.
750 |
751 | Especially the message body might be useful to extend the limit for.
752 |
753 | \begin{itemize}
754 | \item 64 bytes for header name
755 | \item 512 bytes for header value
756 | \item 32 header pairs
757 | \item 16 Megabyte for the body.
758 | \end{itemize}
759 |
760 | \subsubsection*{Examples}
761 |
762 | \begin{itemize}
763 | \item \code{first=Foo,second=Bar;some body here}
764 | \item \code{,first=Foo,second,,,another=value,also=;some body here}
765 | \item \code{message=!SGVsbG8gV29ybGQ=} (no body, only one Base64 encoded header)
766 | \item \code{;!SGVsbG8gV29ybGQ=} (no headers, only one Base64 encoded body)
767 | \end{itemize}
768 |
769 | % }}}
770 | \subsection{Feature Detection} % {{{
771 |
772 | Syntax: \DA
773 |
774 | \DA's response code for detecting support for an implementation of this specification is \code{11}.
775 |
776 | % }}}
777 | \subsection{Upload Image} % {{{
778 |
779 | Syntax: \code{OSC 314 ; u ; ST}
780 |
781 | The payload's format is mandated by the \code{fmt}'s value. However, since it must not contain
782 | any C0 or C1 escape codes, the transport is further protected by encoding it via Base64.
783 |
784 | \subsubsection*{Parameters}
785 |
786 | \begin{tabular}{|m{3cm}|m{2cm}|m{11cm}|}
787 | \hline
788 | \textbf{header name} & \textbf{title} & \textbf{notes} \\
789 | \hline
790 | \textbf{n} & name & unique name of the image \\
791 | \textbf{W} & width & number of image width of the uploaded image (not needed for PNG) \\
792 | \textbf{H} & height & number of image height of the uploaded image (not needed for PNG) \\
793 | \textbf{F} & format & enum (see section \ref{sec:supported-image-formtats}) \\
794 | \hline
795 | \end{tabular}
796 |
797 | The message body contains the image data.
798 |
799 | \subsubsection*{Example}
800 |
801 | This is a small Bash shell example that is uploading a PNG image with a fixed ID.
802 |
803 | \begin{verbatim}
804 | # Shell function demonstrating how to upload an image:
805 | function gip_upload() {
806 | local ImageId=$(echo -ne "org.yourdomain.yourtool.$1" | base64 -)
807 | local ImageData=$(base64 "$2")
808 | local ImageFormat=3 # 3=PNG
809 | echo -ne "\033P314;u;F=${ImageFormat},n=${ImageId};!${ImageData}\033\\"
810 | }
811 | \end{verbatim}
812 |
813 | \pagebreak
814 |
815 | % }}}
816 | \subsection{Render Image} % {{{
817 |
818 | Syntax: \code{OSC 314 ; r ; ST}
819 |
820 | \subsubsection*{Message parameters}
821 |
822 | \begin{tabular}{|m{3cm}|m{2cm}|m{11cm}|}
823 | \hline
824 | \textbf{message header} & \textbf{title} & \textbf{Value} \\
825 | \hline
826 | \textbf{n} & name & image Id as string \\
827 | \textbf{z} & screen-layer & Render image below text (0), replace text (1), above text (2) \\
828 | \textbf{L} & screen-left & screen column of the image's left (if not given, the current ANSI text cursor location is used) \\
829 | \textbf{T} & screen-top & screen row of the image's top (if not given, the current ANSI text cursor location is used) \\
830 | \textbf{c} & screen-cols & number of columns this image will be printed on \\
831 | \textbf{r} & screen-rows & number of rows the image will be printed on \\
832 | \textbf{x} & image-x-offset & x-offset into the referenced image in screen coordinates (used to render only parts of the image) \\
833 | \textbf{y} & image-y-offset & y-offset into the referenced image in screen coordinates (used to render only parts of the image) \\
834 | \textbf{w} & image-width & width of the referenced image in screen coordinates (used to render only parts of the image) \\
835 | \textbf{h} & image-height & height of the referenced image in screen coordinates (used to render only parts of the image) \\
836 | \textbf{R} & resize-policy & one of: \\ % TODO: defaults should have the lowest value (=> 1)
837 | & & 1 (NoResize), 2 (ResizeToFit), 3 (ResizeToFill), 4 (StretchToFill) \\
838 | \textbf{a} & alignment-policy & one of: \\
839 | & & 1 (MiddleCenter), 2 (MiddleStart), 3 (MiddleEnd), \\
840 | & & 4 (TopStart), 5 (TopCenter), 6 (TopEnd), \\
841 | & & 7 (BottomStart), 8 (BottomCenter), 9 (BottomEnd) \\
842 | \textbf{t} & update-cursor & boolean indicating to move the ANSI text cursor \\
843 | \textbf{s} & status & one of: 1 (request status response), 0 otherwise (default) \\
844 | \hline
845 | \end{tabular}
846 |
847 | \subsubsection*{Response Sequence}
848 |
849 | When a response status code was requested, the syntax will be as follows:
850 |
851 | \begin{tabular}{ |r|l| }
852 | \hline
853 | \textbf{VT sequence} & \textbf{description} \\
854 | \hline
855 | \code{CSI > 0 i} & Image is rendered successfully \\
856 | \code{CSI > 1 i} & Image was not rendered. No image with the given Id found. \\
857 | \hline
858 | \end{tabular}
859 |
860 | \subsubsection*{Example}
861 |
862 | \begin{verbatim}
863 | # Shell function demonstrating how to render an image:
864 | function render_image() {
865 | # Rendering the given image at the current cursor position with a 20x10 size.
866 | local ImageId=$(echo -ne "org.binutils.ls.$1" | base64 -)
867 | local ScreenColumns="20"
868 | local ScreenLines="10"
869 | echo -ne "\033P314;r;1;c=${ScreenColumns};r=:${ScreenLines}n=${ImageId}\033\\"
870 | }
871 | \end{verbatim}
872 |
873 | % }}}
874 | \subsection{Upload and Render Image} % {{{
875 |
876 | Syntax: \code{OSC 314 ; s ; ST}
877 |
878 | \subsubsection*{Numerical parameters}
879 |
880 | \begin{tabular}{|m{3cm}|m{2cm}|m{11cm}|}
881 | \hline
882 | \textbf{message header} & \textbf{title} & \textbf{Value} \\
883 | \hline
884 | \textbf{W} & width & number of image width of the uploaded image (not needed for PNG) \\
885 | \textbf{H} & height & number of image height of the uploaded image (not needed for PNG) \\
886 | \textbf{F} & format & enum (see section \ref{sec:supported-image-formtats}) \\
887 | \hline
888 | \textbf{z} & screen-layer & Render image below text (0), replace text (1), above text (2) \\
889 | \textbf{L} & screen-left & screen column of the image's left (if not given, the current ANSI text cursor location is used) \\
890 | \textbf{T} & screen-top & screen row of the image's top (if not given, the current ANSI text cursor location is used) \\
891 | \textbf{c} & screen-cols & number of columns this image will be printed on \\
892 | \textbf{r} & screen-rows & number of rows the image will be printed on \\
893 | \textbf{x} & image-x-offset & x-offset into the referenced image in screen coordinates (used to render only parts of the image) \\
894 | \textbf{y} & image-y-offset & y-offset into the referenced image in screen coordinates (used to render only parts of the image) \\
895 | \textbf{w} & image-width & width of the referenced image in screen coordinates (used to render only parts of the image) \\
896 | \textbf{h} & image-height & height of the referenced image in screen coordinates (used to render only parts of the image) \\
897 | \textbf{R} & resize-policy & one of: \\ % TODO: defaults should have the lowest value (=> 1)
898 | & & 1 (NoResize), 2 (ResizeToFit), 3 (ResizeToFill), 4 (StretchToFill) \\
899 | \textbf{a} & alignment-policy & one of: \\
900 | & & 1 (MiddleCenter), 2 (MiddleStart), 3 (MiddleEnd), \\
901 | & & 4 (TopStart), 5 (TopCenter), 6 (TopEnd), \\
902 | & & 7 (BottomStart), 8 (BottomCenter), 9 (BottomEnd) \\
903 | \textbf{t} & update-cursor & boolean indicating to move the ANSI text cursor \\
904 | \textbf{s} & status & one of: 1 (request status response), 0 otherwise \\
905 | \hline
906 | \end{tabular}
907 |
908 | \subsubsection*{Example}
909 |
910 | This is a small Bash shell example that is uploading a PNG image with a fixed ID.
911 |
912 | \begin{verbatim}
913 | # Shell function demonstrating how to render a oneshot image:
914 | function send_image_once() {
915 | local ImageData=$(base64 "$1")
916 | local ImageFormat="png"
917 | local GridWidth="20"
918 | local GridHeight="10"
919 | echo -ne "\033P314;s;F:${ImageFormat};c:${GridWidth};r:${GridHeight}s${ImageData}\033\\"
920 | }
921 | \end{verbatim}
922 |
923 | % }}}
924 | \subsection{Release Image} % {{{
925 |
926 | Syntax: \code{OSC 314 ; d ; ST}
927 |
928 | \subsubsection*{Message parameters}
929 |
930 | \begin{tabular}{ |c|c|l| }
931 | \hline
932 | \textbf{header name} & \textbf{title} & \textbf{notes} \\
933 | \hline
934 | \textbf{n} & name & unique name of the image \\
935 | \hline
936 | \end{tabular}
937 |
938 | % }}}
939 | % }}}
940 | \section{Supported Image Formats} % {{{
941 |
942 | \label{sec:supported-image-formtats}
943 |
944 | \begin{tabular}{c | c | l}
945 | File Format & Identifier & Description \\
946 | \hline
947 | RGB & \code{rgb} & raw RGB data with each color component being of size 1 byte. \\
948 | RGBA & \code{rgba} & raw RGBA data, just like RGB, but with an alpha channel. \\
949 | PNG & \code{png} & PNG file format \\
950 | Sixel & \code{sixel} & Payload is given in sixel encoding. \\
951 | \hline
952 | \end{tabular}
953 |
954 | \todo{I think it make sense to use mimetype as values instead?}
955 |
956 | % }}}
957 | \section{Future Modifications} % {{{
958 |
959 | Possible future modifications could (but do not have to) cover:
960 |
961 | \begin{itemize}
962 | \item Set and reset resource limits.
963 | \item Query allocated resource names.
964 | \item Query resource utilization.
965 | \item Direct support of animations.
966 | \item Different transport encodings (other than Base64).
967 | \item Extending the use of uploaded images to also be used for application / window / tab icons.
968 | \item Extending the use of uploaded images to terminal background.
969 | \end{itemize}
970 |
971 | % }}}
972 | \section{References} % {{{
973 |
974 | \begin{enumerate}
975 | \item \label{ref:ctlseqs}\url{https://invisible-island.net/xterm/ctlseqs/ctlseqs.txt}
976 | \item \label{ref:twg-simple-image-display}Simple Image display, \url{https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/12}
977 | \item \label{ref:twg-gip}Good Image Protocol, \url{https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/26}
978 | \item \label{ref:image-sixel}Sixel Image Protocol, \url{https://vt100.net/docs/vt3xx-gp/chapter14.html}
979 | \item \label{ref:image-item2}iTerm2's image protocol, \url{https://iterm2.com/documentation-images.html}
980 | \item \label{ref:image-terminology}Terminology's image protocol, \url{https://github.com/borisfaure/terminology/blob/master/README.md#available-commands}
981 | \item \label{ref:image-kitty}Kitty's image protocol, \url{https://sw.kovidgoyal.net/kitty/graphics-protocol.html}
982 | \end{enumerate}
983 |
984 | % }}}
985 | \section{Editorial Notes} % {{{
986 |
987 | \begin{itemize}
988 | \item Maybe use tables instead of lists for parameter listings?
989 | \item Should we mention how to deal with HiDPI displays and content scaling?
990 | \item How to implement a cat-like tool for images without breaking determinism for proxy
991 | terminals (like tmux).
992 | I.e. how does the proxy terminal know about how many rows will be used when
993 | a pixel perfect rendering is attempted (resize-policy set to NoResize,
994 | screen-cols=\$COLUMNS). But what is row count?
995 | I think the only way to achieve that if that image-cat tool peaks into
996 | the image dimensions and calculates a maybe perfect number of rows
997 | based on that and the retrieved pixel height (which is not recommended though).
998 | \item Do we want to deal with transparent pixels differently?
999 | \item Is it \textbf{really} necessary to be able to render above/below text with preserving the
1000 | text? What is the real use case for that? (that would require the introduction of a z-axis).
1001 | \item If so, can images be layered, therefore can a cell have more than one image.
1002 | And what is happening if the above image is removed. Will the image below be shown?
1003 | \item Should SGRs be usable in screen cells showing image fragments?
1004 | \end{itemize}
1005 |
1006 | % }}}
1007 |
1008 | \listoftodos
1009 |
1010 | \end{document}
1011 |
1012 | % vim:ts=4:sw=4
1013 |
--------------------------------------------------------------------------------