Skip to content

Commit 413a8d5

Browse files
authored
Merge pull request #2 from trackd/feature/InlineImageProtocol
Feature/inline image protocol
2 parents 3c0aec1 + c879f94 commit 413a8d5

22 files changed

+689
-383
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ We test against the latest Windows Terminal Preview.
2626

2727
Sixel support has not been added to Windows Terminal Stable branch yet.
2828

29+
There is an example sixel file in the ./assets folder that can be used for testing
30+
31+
```powershell
32+
# test sixel
33+
Invoke-RestMethod https://raw.githubusercontent.com/trackd/Sixel/refs/heads/main/assets/chibi.six
34+
```
35+
2936
## Authors
3037

3138
**[@trackd](https://github.com/trackd)**

Sixel.sln

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.5.002.0
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{343B7D25-9E8D-49CD-8CE2-5AEFB55599AA}"
7+
EndProject
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sixel", "src\Sixel\Sixel.csproj", "{6530F44D-2FF4-4BE5-ACD7-BC7BB16A0036}"
9+
EndProject
10+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sixel.Shared", "src\Sixel.Shared\Sixel.Shared.csproj", "{CEA8ABE2-8256-4318-9C2C-20ED7483F7A7}"
11+
EndProject
12+
Global
13+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
14+
Debug|Any CPU = Debug|Any CPU
15+
Release|Any CPU = Release|Any CPU
16+
EndGlobalSection
17+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
18+
{6530F44D-2FF4-4BE5-ACD7-BC7BB16A0036}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19+
{6530F44D-2FF4-4BE5-ACD7-BC7BB16A0036}.Debug|Any CPU.Build.0 = Debug|Any CPU
20+
{6530F44D-2FF4-4BE5-ACD7-BC7BB16A0036}.Release|Any CPU.ActiveCfg = Release|Any CPU
21+
{6530F44D-2FF4-4BE5-ACD7-BC7BB16A0036}.Release|Any CPU.Build.0 = Release|Any CPU
22+
{CEA8ABE2-8256-4318-9C2C-20ED7483F7A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23+
{CEA8ABE2-8256-4318-9C2C-20ED7483F7A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
24+
{CEA8ABE2-8256-4318-9C2C-20ED7483F7A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
25+
{CEA8ABE2-8256-4318-9C2C-20ED7483F7A7}.Release|Any CPU.Build.0 = Release|Any CPU
26+
EndGlobalSection
27+
GlobalSection(SolutionProperties) = preSolution
28+
HideSolutionNode = FALSE
29+
EndGlobalSection
30+
GlobalSection(NestedProjects) = preSolution
31+
{6530F44D-2FF4-4BE5-ACD7-BC7BB16A0036} = {343B7D25-9E8D-49CD-8CE2-5AEFB55599AA}
32+
{CEA8ABE2-8256-4318-9C2C-20ED7483F7A7} = {343B7D25-9E8D-49CD-8CE2-5AEFB55599AA}
33+
EndGlobalSection
34+
GlobalSection(ExtensibilityGlobals) = postSolution
35+
SolutionGuid = {E8BEDC54-6143-4441-AB0F-E25E9C81A141}
36+
EndGlobalSection
37+
EndGlobal

docs/en-US/ConvertTo-Sixel.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,12 @@ Accept pipeline input: False
114114
Accept wildcard characters: False
115115
```
116116
117-
### -PixelWidth
117+
### -Force
118118
119-
Width of the image in Pixels, the height will be scaled to maintain aspect ratio
119+
Force the command to attempt to output sixel data even if the terminal does not support sixel.
120120
121121
```yaml
122-
Type: int
122+
Type: SwitchParameter
123123
Parameter Sets: (All)
124124
Aliases:
125125

@@ -130,12 +130,12 @@ Accept pipeline input: False
130130
Accept wildcard characters: False
131131
```
132132
133-
### -Force
133+
### -Protocol
134134
135-
Force the command to attempt to output sixel data even if the terminal does not support sixel.
135+
Select the image protocol to output, supports Sixel & InlineImageProtocol (1337 xterm).
136136
137137
```yaml
138-
Type: SwitchParameter
138+
Type: ImageProtocol
139139
Parameter Sets: (All)
140140
Aliases:
141141

module/Sixel.psd1

+17-8
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,38 @@
44

55
@{
66
RootModule = 'Sixel.psm1'
7-
ModuleVersion = '0.2.0'
7+
ModuleVersion = '0.2.5'
88
CompatiblePSEditions = 'Core'
99
PowerShellVersion = '7.4'
1010
GUID = '95f4627c-f8f5-43d5-824b-4c356737f87b'
1111
Author = 'trackd, ShaunLawrie'
1212
Copyright = '(c) trackd. All rights reserved.'
13-
Description = 'Convert images to Sixel format and display them in the terminal'
13+
Description = 'Convert images to Sixel format and display them in the terminal, Requires a terminal with Sixel support. (Windows Terminal v1.22.2912.0 or later) or Inline Image Protocol support.'
1414
CmdletsToExport = @('ConvertTo-Sixel')
15-
AliasesToExport = @('cts')
15+
AliasesToExport = @('cts', 'ConvertTo-InlineImage')
1616
PrivateData = @{
1717
PSData = @{
18-
Tags = @(
18+
Tags = @(
1919
'Sixel',
2020
'Terminal',
2121
'Graphics',
22-
'Image'
22+
'Image',
23+
'Console Image',
24+
'Inline Image Protocol',
25+
'xterm image'
2326
)
24-
LicenseUri = 'https://github.com/trackd/Sixel/blob/main/LICENSE'
25-
ProjectUri = 'https://github.com/trackd/Sixel'
27+
LicenseUri = 'https://github.com/trackd/Sixel/blob/main/LICENSE'
28+
ProjectUri = 'https://github.com/trackd/Sixel'
2629
ReleaseNotes = @'
27-
0.2.0 - Added better scaling, changes -Width to use cell width instead, the old scaling is accessible through -PixelWidth
30+
0.2.5 - bugfix, cleanup, added experimental support for inline image protocol.
31+
0.2.0 - Added better scaling, changes -Width to use cell width instead
2832
0.1.0 - Initial release
2933
'@
3034
}
3135
}
36+
# A missing or $null entry is equivalent to specifying the wildcard *. declare unused with @() for better perf.
37+
FunctionsToExport = @()
38+
VariablesToExport = @()
39+
FormatsToProcess = @()
40+
TypesToProcess = @()
3241
}

src/Sixel/Cmdlet/SixelCmdlet.cs

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
using Sixel.Terminal;
2+
using Sixel.Terminal.Models;
3+
using System.Management.Automation;
4+
5+
namespace Sixel.Cmdlet;
6+
7+
[Cmdlet(VerbsData.ConvertTo, "Sixel", DefaultParameterSetName = "Path")]
8+
[Alias("cts", "ConvertTo-InlineImage")]
9+
[OutputType(typeof(string))]
10+
public sealed class ConvertSixelCmdlet : PSCmdlet
11+
{
12+
[Parameter(
13+
HelpMessage = "A path to a local image to convert to sixel.",
14+
Mandatory = true,
15+
ValueFromPipelineByPropertyName = true,
16+
Position = 0,
17+
ParameterSetName = "Path"
18+
)]
19+
[ValidateNotNullOrEmpty]
20+
[Alias("FullName")]
21+
public string Path { get; set; } = null!;
22+
23+
[Parameter(
24+
HelpMessage = "A URL of the image to download and convert to sixel.",
25+
Mandatory = true,
26+
ValueFromPipeline = true,
27+
ParameterSetName = "Url"
28+
)]
29+
[ValidateNotNullOrEmpty]
30+
[Alias("Uri")]
31+
public string Url { get; set; } = null!;
32+
33+
[Parameter(
34+
HelpMessage = "The maximum number of colors to use in the image."
35+
)]
36+
[ValidateRange(1, 256)]
37+
public int MaxColors { get; set; } = 256;
38+
39+
[Parameter(
40+
HelpMessage = "Width of the image in character cells, the height will be scaled to maintain aspect ratio."
41+
)]
42+
[ValidateTerminalWidth()]
43+
public int Width { get; set; }
44+
45+
[Parameter(
46+
HelpMessage = "Force the command to attempt to output sixel data even if the terminal does not support sixel."
47+
)]
48+
public SwitchParameter Force { get; set; }
49+
50+
[Parameter(
51+
HelpMessage = "Choose ImageProtocol to use for conversion."
52+
)]
53+
public ImageProtocol Protocol { get; set; } = Compatibility.GetTerminalInfo().Protocol;
54+
protected override void ProcessRecord()
55+
{
56+
try
57+
{
58+
Stream? imageStream = null;
59+
switch (ParameterSetName)
60+
{
61+
case "Path":
62+
{
63+
var resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(Path)[0].Path;
64+
imageStream = new FileStream(resolvedPath, FileMode.Open, FileAccess.Read);
65+
break;
66+
}
67+
case "Url":
68+
{
69+
using var client = new HttpClient();
70+
var response = client.GetAsync(Url).Result;
71+
response.EnsureSuccessStatusCode();
72+
imageStream = response.Content.ReadAsStream();
73+
break;
74+
}
75+
}
76+
if (imageStream is null) return;
77+
using (imageStream)
78+
{
79+
WriteObject(
80+
Load.ConsoleImage(
81+
Protocol,
82+
imageStream,
83+
MaxColors,
84+
Width,
85+
Force.IsPresent
86+
)
87+
);
88+
}
89+
}
90+
catch (Exception ex)
91+
{
92+
WriteError(new ErrorRecord(ex, "SixelError", ErrorCategory.NotSpecified, null));
93+
}
94+
}
95+
}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Sixel.Terminal;
2+
using System.Text;
3+
4+
namespace Sixel.Protocols;
5+
6+
public static class InlineImage
7+
{
8+
/// <summary>
9+
/// Converts an image to an inline image protocol string.
10+
/// </summary>
11+
internal static string ImageToInline(Stream image)
12+
{
13+
using var ms = new MemoryStream();
14+
image.CopyTo(ms);
15+
var imageBytes = ms.ToArray();
16+
var base64Image = Convert.ToBase64String(imageBytes);
17+
var iip = new StringBuilder();
18+
iip.Append(Constants.INLINEIMAGESTART)
19+
.Append("1337;File=inline=1")
20+
.Append(";width=auto")
21+
.Append(";height=auto")
22+
.Append(";preserveAspectRatio=1:")
23+
.Append(base64Image)
24+
.Append(Constants.INLINEIMAGEEND);
25+
return iip.ToString();
26+
}
27+
}

0 commit comments

Comments
 (0)