Skip to content

Commit 55225eb

Browse files
committed
Add SIXEL terminal images article
1 parent f1ab960 commit 55225eb

3 files changed

Lines changed: 241 additions & 0 deletions

File tree

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
---
2+
title: "PowerShell Can Put Pictures in Your Terminal with SIXEL"
3+
description: "Render PNG, JPEG, and SVG images inside iTerm2 with a PowerShell cmdlet and SIXEL, with a tested macOS demo and an invitation to try Windows Terminal."
4+
author: Andrey Vernigora
5+
authors:
6+
- Andrey Vernigora
7+
date: "2026-09-03T00:00:00+00:00"
8+
categories:
9+
- Tools
10+
tags:
11+
- powershell
12+
- sixel
13+
- iterm2
14+
- windows-terminal
15+
- terminal-graphics
16+
---
17+
18+
PowerShell normally sends text and objects to a terminal. This experiment sends an image.
19+
20+
```powershell
21+
Out-Sixel -Path ./sixel-demo.svg -Width 480
22+
```
23+
24+
Instead of opening Preview or a browser, the command decodes the SVG, converts it into a palette, and writes a stream of terminal escape sequences. iTerm2 interprets those sequences and paints the image directly between the command and the next prompt.
25+
26+
This is mostly for fun. It is also a useful reminder that a terminal is a protocol endpoint, not merely a grid of characters.
27+
28+
> [!NOTE]
29+
> **Tested environment:** macOS 26.6.2, iTerm2 3.6.11, PowerShell 7.6.1, Apple Silicon.
30+
>
31+
> The direct iTerm2 session is the tested path in this article. No tmux or screen sits between PowerShell and the terminal.
32+
33+
![Out-Sixel rendering an SVG directly inside a PowerShell session in iTerm2](/images/articles/powershell-sixel/out-sixel-iterm.gif)
34+
35+
The recording above is a real iTerm2 session. The command reads the SVG, writes SIXEL escape sequences to the terminal, and returns to the PowerShell prompt after iTerm2 renders the image.
36+
37+
![The PowerShell plus SIXEL SVG used by the terminal demo](/images/articles/powershell-sixel/sixel-demo.svg)
38+
39+
The image above is the source file used in the recording. [Download the demo SVG](/images/articles/powershell-sixel/sixel-demo.svg) and save it as `sixel-demo.svg` to run the opening command.
40+
41+
## What is SIXEL?
42+
43+
[SIXEL](https://vt100.net/docs/vt3xx-gp/chapter14.html) is a bitmap graphics format originally used by DEC terminals and printers. The name comes from its basic unit: a character represents a vertical group of six pixels.
44+
45+
A SIXEL image is still text from the process's point of view. It begins with a device-control escape sequence, contains a palette and encoded pixel bands, and ends with a string terminator. A compatible terminal recognizes that stream as graphics rather than printable characters.
46+
47+
That old design has one property that remains attractive: the image travels over the same channel as terminal output. There is no separate window, web server, or GUI API.
48+
49+
## The PowerShell experiment
50+
51+
The command is part of an experimental C# port of [libsixel](https://github.com/saitoha/libsixel). My [C# port repository](https://github.com/eosfor/libsixel) contains a small PowerShell module whose public surface is the compiled `Out-Sixel` cmdlet.
52+
53+
Install the exact [LibSixel.PowerShell 0.2.0-beta2](https://github.com/eosfor/libsixel/releases/tag/v0.2.0-beta2) prerelease used by this article from PowerShell Gallery:
54+
55+
```powershell
56+
Install-Module `
57+
-Name LibSixel.PowerShell `
58+
-RequiredVersion '0.2.0-beta2' `
59+
-AllowPrerelease `
60+
-Scope CurrentUser
61+
62+
Import-Module LibSixel.PowerShell
63+
```
64+
65+
Then confirm that PowerShell can see the compiled cmdlet:
66+
67+
```powershell
68+
Get-Command Out-Sixel
69+
```
70+
71+
The cmdlet accepts PNG, JPEG, and SVG files:
72+
73+
```powershell
74+
Out-Sixel -Path ./photo.png
75+
Out-Sixel -Path ./photo.jpg
76+
Out-Sixel -Path ./diagram.svg
77+
```
78+
79+
Large images should be resized before encoding. `-Width` and `-Height` accept pixel dimensions; specifying only one preserves the aspect ratio:
80+
81+
```powershell
82+
Out-Sixel -Path ./photo.jpg -Width 480
83+
Out-Sixel -Path ./diagram.svg -Height 260
84+
```
85+
86+
SIXEL uses a limited palette. The default is 256 colors, but a smaller palette can reduce the output considerably:
87+
88+
```powershell
89+
Out-Sixel -Path ./photo.jpg -Width 480 -Colors 64
90+
```
91+
92+
The result will not compete with a normal image viewer. That is part of the charm: the encoder applies color quantization and dithering, giving photographs a slightly retro character while diagrams usually remain crisp.
93+
94+
## Render an SVG without creating a file
95+
96+
`Out-Sixel` also recognizes SVG content arriving through the pipeline. This makes a self-contained demo possible:
97+
98+
```powershell
99+
$svg = @'
100+
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="240">
101+
<defs>
102+
<linearGradient id="g" x1="0" x2="1">
103+
<stop offset="0" stop-color="#38bdf8" />
104+
<stop offset="1" stop-color="#8b5cf6" />
105+
</linearGradient>
106+
</defs>
107+
<rect width="640" height="240" rx="24" fill="#111827" />
108+
<text x="320" y="105" text-anchor="middle"
109+
font-family="monospace" font-size="38" fill="url(#g)">
110+
PowerShell + SIXEL
111+
</text>
112+
<text x="320" y="160" text-anchor="middle"
113+
font-family="monospace" font-size="20" fill="#cbd5e1">
114+
no browser required
115+
</text>
116+
</svg>
117+
'@
118+
119+
$svg | Out-Sixel -Width 480
120+
```
121+
122+
This is an entertaining way to display a generated diagram or status card. It is not a replacement for structured PowerShell output: once data becomes pixels, the pipeline can no longer filter or sort it.
123+
124+
## What happens inside the command?
125+
126+
The path from a file to the terminal is deliberately small:
127+
128+
```text
129+
PNG / JPEG / SVG
130+
|
131+
v
132+
SkiaSharp decode or SVG rasterization
133+
|
134+
v
135+
RGBA pixel buffer
136+
|
137+
v
138+
palette selection and dithering
139+
|
140+
v
141+
SIXEL escape sequence
142+
|
143+
v
144+
iTerm2 renders the pixels
145+
```
146+
147+
SkiaSharp decodes PNG and JPEG inputs. `Svg.Skia` rasterizes SVG into the same RGBA representation. The ported libsixel code then selects a palette, applies dithering, and writes the SIXEL device-control string through `Host.UI`.
148+
149+
The command can return that string instead of writing it to the terminal:
150+
151+
```powershell
152+
$sixel = Out-Sixel -Path ./diagram.svg -Width 480 -AsString
153+
154+
[int][char]$sixel[0]
155+
[int][char]$sixel[1]
156+
```
157+
158+
The first two values are `27` and `80`: `ESC` followed by `P`, the beginning of a device-control string.
159+
160+
## Exactly where does it work?
161+
162+
Terminal support matters more than the shell prompt. The same `pwsh` command can display an image in one terminal and produce garbage in another.
163+
164+
| Environment | Status for this experiment |
165+
| --- | --- |
166+
| **iTerm2 3.3 or newer on macOS** | Supported. This article was tested with iTerm2 3.6.11. |
167+
| **PowerShell 7.4 or newer** | Required by the current `net8.0` module build. This article was tested with PowerShell 7.6.1. |
168+
| **Windows Terminal 1.22 or newer** | SIXEL is supported by the terminal, and the module includes Windows Skia native assets. I have not tested this combination yet—please try it and report what you find. |
169+
| **Windows PowerShell 5.1** | Not supported. It cannot load this `net8.0` module. |
170+
| **macOS Terminal.app and the VS Code integrated terminal** | Not tested and not claimed as supported here. |
171+
| **tmux and screen** | Outside the supported path. A multiplexer may filter the escape sequence or require its own SIXEL configuration. |
172+
173+
[iTerm2 has supported SIXEL since its 3.3 release](https://iterm2.com/downloads/stable/iTerm2-3_3_0.changelog), and recent releases continue to fix SIXEL decoding. [Windows Terminal introduced support in version 1.22](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-22-release/). These version boundaries are about the terminal emulator; the module independently requires a modern PowerShell runtime.
174+
175+
## Windows Terminal readers: please try this
176+
177+
I deliberately kept the Windows claim separate from the macOS result. The renderer exists in Windows Terminal, and the module packages the Windows Skia native library, but a real end-to-end run is more valuable than an inference from two codebases.
178+
179+
If you have Windows Terminal 1.22 or newer and PowerShell 7.4 or newer, try:
180+
181+
```powershell
182+
$PSVersionTable.PSVersion
183+
184+
Get-AppxPackage Microsoft.WindowsTerminal |
185+
Select-Object Name, Version
186+
187+
Install-Module -Name LibSixel.PowerShell -RequiredVersion '0.2.0-beta2' -AllowPrerelease -Scope CurrentUser
188+
Import-Module LibSixel.PowerShell
189+
190+
# Use the inline $svg sample from the earlier section.
191+
$svg | Out-Sixel -Width 480
192+
```
193+
194+
If it works, capture the terminal version, PowerShell version, architecture, and a screenshot. If it does not, the failure mode is just as useful: dependency loading, raw escape text, a blank area, or incorrect cursor placement point to different layers.
195+
196+
## Limitations worth keeping
197+
198+
This is an experiment, not a new universal image API for PowerShell.
199+
200+
- SIXEL palettes contain at most 256 colors.
201+
- Large images produce large terminal streams and can be slow over remote connections.
202+
- Image placement and cursor behavior vary between terminal implementations.
203+
- Multiplexers add another protocol layer and need separate testing.
204+
- SVG text depends on fonts available to Skia on the machine doing the rasterization.
205+
- The module is an experimental prerelease rather than a stable terminal graphics API.
206+
207+
Those constraints keep the example honest, but they do not make it less fun. A generated architecture diagram, chart, QR code, or build badge appearing directly in a PowerShell session is still a delightful result from a protocol designed decades ago.
208+
209+
## Takeaway
210+
211+
The surprising part is not that PowerShell can read an image. The surprising part is that the ordinary terminal output channel can carry the image all the way to the screen.
212+
213+
On macOS with iTerm2, that path works today:
214+
215+
```text
216+
PowerShell -> SIXEL -> iTerm2 -> pixels
217+
```
218+
219+
Windows Terminal should provide the same path on Windows. If you test it, send the result. One successful screenshot—or one interesting failure—would make a useful follow-up to this little experiment.
231 KB
Loading
Lines changed: 22 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)