-
Notifications
You must be signed in to change notification settings - Fork 700
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3734 from tznind/sixel-encoder-tinkering
Fixes #1265 - Adds Sixel rendering support
- Loading branch information
Showing
19 changed files
with
2,094 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
namespace Terminal.Gui; | ||
|
||
/// <summary> | ||
/// Implementation of <see cref="ISixelSupportDetector"/> that assumes best | ||
/// case scenario (full support including transparency with 10x20 resolution). | ||
/// </summary> | ||
public class AssumeSupportDetector : ISixelSupportDetector | ||
{ | ||
/// <inheritdoc/> | ||
public SixelSupportResult Detect () | ||
{ | ||
return new() | ||
{ | ||
IsSupported = true, | ||
MaxPaletteColors = 256, | ||
Resolution = new (10, 20), | ||
SupportsTransparency = true | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
namespace Terminal.Gui; | ||
|
||
/// <summary> | ||
/// Interface for detecting sixel support. Either through | ||
/// ansi requests to terminal or config file etc. | ||
/// </summary> | ||
public interface ISixelSupportDetector | ||
{ | ||
/// <summary> | ||
/// Gets the supported sixel state e.g. by sending Ansi escape sequences | ||
/// or from a config file etc. | ||
/// </summary> | ||
/// <returns>Description of sixel support.</returns> | ||
public SixelSupportResult Detect (); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
using System.Collections.Concurrent; | ||
|
||
namespace Terminal.Gui; | ||
|
||
/// <summary> | ||
/// Translates colors in an image into a Palette of up to <see cref="MaxColors"/> colors (typically 256). | ||
/// </summary> | ||
public class ColorQuantizer | ||
{ | ||
/// <summary> | ||
/// Gets the current colors in the palette based on the last call to | ||
/// <see cref="BuildPalette"/>. | ||
/// </summary> | ||
public IReadOnlyCollection<Color> Palette { get; private set; } = new List<Color> (); | ||
|
||
/// <summary> | ||
/// Gets or sets the maximum number of colors to put into the <see cref="Palette"/>. | ||
/// Defaults to 256 (the maximum for sixel images). | ||
/// </summary> | ||
public int MaxColors { get; set; } = 256; | ||
|
||
/// <summary> | ||
/// Gets or sets the algorithm used to map novel colors into existing | ||
/// palette colors (closest match). Defaults to <see cref="EuclideanColorDistance"/> | ||
/// </summary> | ||
public IColorDistance DistanceAlgorithm { get; set; } = new EuclideanColorDistance (); | ||
|
||
/// <summary> | ||
/// Gets or sets the algorithm used to build the <see cref="Palette"/>. | ||
/// </summary> | ||
public IPaletteBuilder PaletteBuildingAlgorithm { get; set; } = new PopularityPaletteWithThreshold (new EuclideanColorDistance (), 8); | ||
|
||
private readonly ConcurrentDictionary<Color, int> _nearestColorCache = new (); | ||
|
||
/// <summary> | ||
/// Builds a <see cref="Palette"/> of colors that most represent the colors used in <paramref name="pixels"/> image. | ||
/// This is based on the currently configured <see cref="PaletteBuildingAlgorithm"/>. | ||
/// </summary> | ||
/// <param name="pixels"></param> | ||
public void BuildPalette (Color [,] pixels) | ||
{ | ||
List<Color> allColors = new (); | ||
int width = pixels.GetLength (0); | ||
int height = pixels.GetLength (1); | ||
|
||
for (var x = 0; x < width; x++) | ||
{ | ||
for (var y = 0; y < height; y++) | ||
{ | ||
allColors.Add (pixels [x, y]); | ||
} | ||
} | ||
|
||
_nearestColorCache.Clear (); | ||
Palette = PaletteBuildingAlgorithm.BuildPalette (allColors, MaxColors); | ||
} | ||
|
||
/// <summary> | ||
/// Returns the closest color in <see cref="Palette"/> that matches <paramref name="toTranslate"/> | ||
/// based on the color comparison algorithm defined by <see cref="DistanceAlgorithm"/> | ||
/// </summary> | ||
/// <param name="toTranslate"></param> | ||
/// <returns></returns> | ||
public int GetNearestColor (Color toTranslate) | ||
{ | ||
if (_nearestColorCache.TryGetValue (toTranslate, out int cachedAnswer)) | ||
{ | ||
return cachedAnswer; | ||
} | ||
|
||
// Simple nearest color matching based on DistanceAlgorithm | ||
var minDistance = double.MaxValue; | ||
var nearestIndex = 0; | ||
|
||
for (var index = 0; index < Palette.Count; index++) | ||
{ | ||
Color color = Palette.ElementAt (index); | ||
double distance = DistanceAlgorithm.CalculateDistance (color, toTranslate); | ||
|
||
if (distance < minDistance) | ||
{ | ||
minDistance = distance; | ||
nearestIndex = index; | ||
} | ||
} | ||
|
||
_nearestColorCache.TryAdd (toTranslate, nearestIndex); | ||
|
||
return nearestIndex; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
namespace Terminal.Gui; | ||
|
||
/// <summary> | ||
/// <para> | ||
/// Calculates the distance between two colors using Euclidean distance in 3D RGB space. | ||
/// This measures the straight-line distance between the two points representing the colors. | ||
/// </para> | ||
/// <para> | ||
/// Euclidean distance in RGB space is calculated as: | ||
/// </para> | ||
/// <code> | ||
/// √((R2 - R1)² + (G2 - G1)² + (B2 - B1)²) | ||
/// </code> | ||
/// <remarks>Values vary from 0 to ~441.67 linearly</remarks> | ||
/// <remarks> | ||
/// This distance metric is commonly used for comparing colors in RGB space, though | ||
/// it doesn't account for perceptual differences in color. | ||
/// </remarks> | ||
/// </summary> | ||
public class EuclideanColorDistance : IColorDistance | ||
{ | ||
/// <inheritdoc/> | ||
public double CalculateDistance (Color c1, Color c2) | ||
{ | ||
int rDiff = c1.R - c2.R; | ||
int gDiff = c1.G - c2.G; | ||
int bDiff = c1.B - c2.B; | ||
|
||
return Math.Sqrt (rDiff * rDiff + gDiff * gDiff + bDiff * bDiff); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace Terminal.Gui; | ||
|
||
/// <summary> | ||
/// Interface for algorithms that compute the relative distance between pairs of colors. | ||
/// This is used for color matching to a limited palette, such as in Sixel rendering. | ||
/// </summary> | ||
public interface IColorDistance | ||
{ | ||
/// <summary> | ||
/// Computes a similarity metric between two <see cref="Color"/> instances. | ||
/// A larger value indicates more dissimilar colors, while a smaller value indicates more similar colors. | ||
/// The metric is internally consistent for the given algorithm. | ||
/// </summary> | ||
/// <param name="c1">The first color.</param> | ||
/// <param name="c2">The second color.</param> | ||
/// <returns>A numeric value representing the distance between the two colors.</returns> | ||
double CalculateDistance (Color c1, Color c2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
namespace Terminal.Gui; | ||
|
||
/// <summary> | ||
/// Builds a palette of a given size for a given set of input colors. | ||
/// </summary> | ||
public interface IPaletteBuilder | ||
{ | ||
/// <summary> | ||
/// Reduce the number of <paramref name="colors"/> to <paramref name="maxColors"/> (or less) | ||
/// using an appropriate selection algorithm. | ||
/// </summary> | ||
/// <param name="colors"> | ||
/// Color of every pixel in the image. Contains duplication in order | ||
/// to support algorithms that weigh how common a color is. | ||
/// </param> | ||
/// <param name="maxColors">The maximum number of colours that should be represented.</param> | ||
/// <returns></returns> | ||
List<Color> BuildPalette (List<Color> colors, int maxColors); | ||
} |
Oops, something went wrong.