├── .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 | --------------------------------------------------------------------------------