diff --git a/docs/en-US/ConvertTo-Sixel.md b/docs/en-US/ConvertTo-Sixel.md index 80e1544..6ab9bc1 100644 --- a/docs/en-US/ConvertTo-Sixel.md +++ b/docs/en-US/ConvertTo-Sixel.md @@ -132,7 +132,10 @@ Accept wildcard characters: False ### -Protocol -Select the image protocol to output, supports Sixel & InlineImageProtocol (1337 xterm). +Select the image protocol to output. +Supports Sixel, InlineImageProtocol, KittyGraphicsProtocol + +It will attempt to autoselect the supported image protocol for your terminal. ```yaml Type: ImageProtocol diff --git a/src/Sixel/Sixel.csproj b/src/Sixel/Sixel.csproj index ae05860..77f6afd 100644 --- a/src/Sixel/Sixel.csproj +++ b/src/Sixel/Sixel.csproj @@ -18,7 +18,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/src/Sixel/Terminal/Compatibility.cs b/src/Sixel/Terminal/Compatibility.cs index d13541e..aded82d 100644 --- a/src/Sixel/Terminal/Compatibility.cs +++ b/src/Sixel/Terminal/Compatibility.cs @@ -1,4 +1,5 @@ using Sixel.Terminal.Models; +using System.Diagnostics; namespace Sixel.Terminal; @@ -9,6 +10,11 @@ public static class Compatibility /// private static bool? _terminalSupportsSixel; + /// + /// Check if the terminal supports kitty graphics + /// + private static bool? _terminalSupportsKitty; + /// /// Memory-caches the result of the terminal cell size. /// @@ -17,8 +23,12 @@ public static class Compatibility /// /// get the terminal info /// - private static TerminalInfo? _terminalInfo; + + private static WindowSizePixels? _windowSizePixels; + + private static WindowSizeCharacters? _windowSizeCharacters; + /// /// Get the cell size of the terminal in pixel-sixel size. /// The response to the command will look like [6;20;10t where the 20 is height and 10 is width. @@ -52,9 +62,55 @@ public static CellSize GetCellSize() PixelHeight = 20 }; } - return _cellSize; } + public static WindowSizePixels GetWindowSizePixels() + { + // this class should be able to re-run, people can resize the terminal + // so should not cache the result.. hopefully this is not too slow + var response14 = GetControlSequenceResponse("[14t"); + try + { + var parts14 = response14.Split(';', 't'); + _windowSizePixels = new WindowSizePixels + { + PixelWidth = int.Parse(parts14[2]), + PixelHeight = int.Parse(parts14[1]), + }; + } + catch + { + _windowSizePixels = new WindowSizePixels + { + PixelWidth = 0, + PixelHeight = 0 + }; + } + return _windowSizePixels; + } + public static WindowSizeCharacters GetWindowSizeCharacters() + { + // this class should be able to re-run, people can resize the terminal + // so should not cache the result.. hopefully this is not too slow + var response18 = GetControlSequenceResponse("[18t"); + try + { + var parts18 = response18.Split(';', 't'); + _windowSizeCharacters = new WindowSizeCharacters + { + CharacterWidth = int.Parse(parts18[2]), + CharacterHeight = int.Parse(parts18[1]), + }; + } + catch { + _windowSizeCharacters = new WindowSizeCharacters + { + CharacterWidth = 0, + CharacterHeight = 0 + }; + } + return _windowSizeCharacters; + } /// /// Check if the terminal supports sixel graphics. @@ -69,17 +125,28 @@ public static bool TerminalSupportsSixel() { return _terminalSupportsSixel.Value; } - _terminalSupportsSixel = GetControlSequenceResponse("[c").Contains(";4;"); - return _terminalSupportsSixel.Value; } /// - /// Send a control sequence to the terminal and read back the response from STDIN. + /// Check if the terminal supports kitty graphics. + /// https://sw.kovidgoyal.net/kitty/graphics-protocol/ + // response: ␛_Gi=31;OK␛\␛[?62;c /// - /// - /// The response from the terminal. + /// True if the terminal supports sixel graphics, false otherwise. + public static bool TerminalSupportsKitty() + { + if (_terminalSupportsKitty.HasValue) + { + return _terminalSupportsKitty.Value; + } + // string kittyTest = $"_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA{Constants.ESC}\\{Constants.ESC}[c"; + string kittyTest = $"_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA{Constants.ESC}\\"; + _terminalSupportsKitty = GetControlSequenceResponse(kittyTest).Contains(";OK"); + return _terminalSupportsKitty.Value; + } + private static string GetControlSequenceResponse(string controlSequence) { char? c; diff --git a/src/Sixel/Terminal/Load.cs b/src/Sixel/Terminal/Load.cs index a30d0d7..17d615f 100644 --- a/src/Sixel/Terminal/Load.cs +++ b/src/Sixel/Terminal/Load.cs @@ -27,6 +27,10 @@ public static class Load } if (imageProtocol == ImageProtocol.KittyGraphicsProtocol) { + if (Compatibility.TerminalSupportsKitty() == false && Force == false) + { + throw new InvalidOperationException("Terminal does not support Kitty, override with -Force"); + } if (width > 0) { // we need to resize the image to the target width diff --git a/src/Sixel/Terminal/Models/WindowSizeCharacters.cs b/src/Sixel/Terminal/Models/WindowSizeCharacters.cs new file mode 100644 index 0000000..de61a93 --- /dev/null +++ b/src/Sixel/Terminal/Models/WindowSizeCharacters.cs @@ -0,0 +1,17 @@ +namespace Sixel.Terminal.Models; + +/// +/// Represents the size of the terminal window in characters. +/// +public class WindowSizeCharacters +{ + /// + /// Gets the width of the terminal in characters. + /// + public int CharacterWidth { get; set; } + + /// + /// Gets the height of the terminal in characters. + /// + public int CharacterHeight { get; set; } +} diff --git a/src/Sixel/Terminal/Models/WindowSizePixels.cs b/src/Sixel/Terminal/Models/WindowSizePixels.cs new file mode 100644 index 0000000..d97d339 --- /dev/null +++ b/src/Sixel/Terminal/Models/WindowSizePixels.cs @@ -0,0 +1,19 @@ +namespace Sixel.Terminal.Models; + +/// +/// Represents the size of the terminal window in pixels +/// not supported in all terminals. +/// like WezTerm, Alacritty +/// +public class WindowSizePixels +{ + /// + /// Gets the width of the terminal in pixels. + /// + public int PixelWidth { get; set; } + + /// + /// Gets the height of the terminal in pixels. + /// + public int PixelHeight { get; set; } +} diff --git a/src/Sixel/Terminal/Validate.cs b/src/Sixel/Terminal/Validate.cs index 76cb50e..8526008 100644 --- a/src/Sixel/Terminal/Validate.cs +++ b/src/Sixel/Terminal/Validate.cs @@ -10,7 +10,7 @@ protected override void Validate(object arguments, EngineIntrinsics engineIntrin { var requestedWidth = (int)arguments; var hostWidth = engineIntrinsics.Host.UI.RawUI.WindowSize.Width; - if (requestedWidth > hostWidth) + if (requestedWidth > hostWidth) { throw new ValidationMetadataException($"{requestedWidth} width is greater than terminal width ({hostWidth})."); }