From db38b35bb74dad33c19fddeb3560257ba337c160 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 17 Feb 2023 22:56:02 +0000 Subject: [PATCH] spinning world --- UICatalog/Scenarios/Animation.cs | 192 +++++++++++++++++++++++++++++++ UICatalog/Scenarios/Images.cs | 123 -------------------- UICatalog/UICatalog.csproj | 3 + 3 files changed, 195 insertions(+), 123 deletions(-) create mode 100644 UICatalog/Scenarios/Animation.cs delete mode 100644 UICatalog/Scenarios/Images.cs diff --git a/UICatalog/Scenarios/Animation.cs b/UICatalog/Scenarios/Animation.cs new file mode 100644 index 000000000..231b0f399 --- /dev/null +++ b/UICatalog/Scenarios/Animation.cs @@ -0,0 +1,192 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Terminal.Gui; +using Attribute = Terminal.Gui.Attribute; + +namespace UICatalog.Scenarios { + [ScenarioMetadata (Name: "Animation", Description: "Demonstration of how to render animated images with threading.")] + [ScenarioCategory ("Colors")] + public class Animation : Scenario + { + private bool isDisposed; + + public override void Setup () + { + base.Setup (); + + var x = 0; + var y = 0; + + var imageView = new ImageView () { + X = x, + Y = y++, + Width = Dim.Fill(), + Height = Dim.Fill(), + }; + Win.Add (imageView); + + var dir = new DirectoryInfo(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); + + var f = new FileInfo( + Path.Combine(dir.FullName,"Scenarios","Spinning_globe_dark_small.gif")); + if(!f.Exists) + { + MessageBox.ErrorQuery("Could not find gif","Could not find "+ f.FullName,"Ok"); + return; + } + + imageView.SetImage(Image.Load (File.ReadAllBytes (f.FullName))); + + Task.Run(()=>{ + while(!isDisposed) + { + Application.MainLoop.Invoke(()=> + { + imageView.NextFrame(); + imageView.SetNeedsDisplay(); + }); + + Task.Delay(100).Wait(); + } + }); + } + + protected override void Dispose(bool disposing) + { + isDisposed = true; + base.Dispose(); + } + + // This is a C# port of https://github.com/andraaspar/bitmap-to-braille by Andraaspar + + /// + /// Renders an image as unicode Braille. + /// + public class BitmapToBraille + { + + public const int CHAR_WIDTH = 2; + public const int CHAR_HEIGHT = 4; + + const string CHARS = " ⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙⡚⡛⡜⡝⡞⡟⠠⠡⠢⠣⠤⠥⠦⠧⡠⡡⡢⡣⡤⡥⡦⡧⠨⠩⠪⠫⠬⠭⠮⠯⡨⡩⡪⡫⡬⡭⡮⡯⠰⠱⠲⠳⠴⠵⠶⠷⡰⡱⡲⡳⡴⡵⡶⡷⠸⠹⠺⠻⠼⠽⠾⠿⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟⢠⢡⢢⢣⢤⢥⢦⢧⣠⣡⣢⣣⣤⣥⣦⣧⢨⢩⢪⢫⢬⢭⢮⢯⣨⣩⣪⣫⣬⣭⣮⣯⢰⢱⢲⢳⢴⢵⢶⢷⣰⣱⣲⣳⣴⣵⣶⣷⢸⢹⢺⢻⢼⢽⢾⢿⣸⣹⣺⣻⣼⣽⣾⣿"; + + public int WidthPixels {get; } + public int HeightPixels { get; } + + public Func PixelIsLit {get;} + + public BitmapToBraille (int widthPixels, int heightPixels, Func pixelIsLit) + { + WidthPixels = widthPixels; + HeightPixels = heightPixels; + PixelIsLit = pixelIsLit; + } + + public string GenerateImage() { + int imageHeightChars = (int) Math.Ceiling((double)HeightPixels / CHAR_HEIGHT); + int imageWidthChars = (int) Math.Ceiling((double)WidthPixels / CHAR_WIDTH); + + var result = new StringBuilder(); + + for (int y = 0; y < imageHeightChars; y++) { + + for (int x = 0; x < imageWidthChars; x++) { + int baseX = x * CHAR_WIDTH; + int baseY = y * CHAR_HEIGHT; + + int charIndex = 0; + int value = 1; + + for (int charX = 0; charX < CHAR_WIDTH; charX++) { + for (int charY = 0; charY < CHAR_HEIGHT; charY++) { + int bitmapX = baseX + charX; + int bitmapY = baseY + charY; + bool pixelExists = bitmapX < WidthPixels && bitmapY < HeightPixels; + + if (pixelExists && PixelIsLit(bitmapX, bitmapY)) { + charIndex += value; + } + value *= 2; + } + } + + result.Append(CHARS[charIndex]); + } + result.Append('\n'); + } + return result.ToString().TrimEnd(); + } + } + + class ImageView : View { + private int frameCount; + private int currentFrame = 0; + + private Image[] fullResImages; + private Image[] matchSizes; + + internal void SetImage (Image image) + { + frameCount = image.Frames.Count; + + fullResImages = new Image[frameCount]; + + for(int i=0;iIsLit(img,x,y)); + + var pix = braille.GenerateImage(); + return pix.Split('\n'); + } + + private bool IsLit (Image img, int x, int y) + { + var rgb = img[x,y]; + return rgb.R + rgb.G + rgb.B > 50; + } + } + } +} \ No newline at end of file diff --git a/UICatalog/Scenarios/Images.cs b/UICatalog/Scenarios/Images.cs deleted file mode 100644 index d0c671b1b..000000000 --- a/UICatalog/Scenarios/Images.cs +++ /dev/null @@ -1,123 +0,0 @@ -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using Terminal.Gui; -using Attribute = Terminal.Gui.Attribute; - -namespace UICatalog.Scenarios { - [ScenarioMetadata (Name: "Images", Description: "Demonstration of how to render an image with/without true color support.")] - [ScenarioCategory ("Colors")] - public class Images : Scenario - { - public override void Setup () - { - base.Setup (); - - var x = 0; - var y = 0; - - var canTrueColor = Application.Driver.SupportsTrueColorOutput; - - var lblDriverName = new Label ($"Current driver is {Application.Driver.GetType ().Name}") { - X = x, - Y = y++ - }; - Win.Add (lblDriverName); - y++; - - var cbSupportsTrueColor = new CheckBox ("Driver supports true color ") { - X = x, - Y = y++, - Checked = canTrueColor, - CanFocus = false - }; - Win.Add (cbSupportsTrueColor); - - var cbUseTrueColor = new CheckBox ("Use true color") { - X = x, - Y = y++, - Checked = Application.Driver.UseTrueColor, - Enabled = canTrueColor, - }; - cbUseTrueColor.Toggled += (_) => Application.Driver.UseTrueColor = cbUseTrueColor.Checked; - Win.Add (cbUseTrueColor); - - var btnOpenImage = new Button ("Open Image") { - X = x, - Y = y++ - }; - Win.Add (btnOpenImage); - - var imageView = new ImageView () { - X = x, - Y = y++, - Width = Dim.Fill(), - Height = Dim.Fill(), - }; - Win.Add (imageView); - - btnOpenImage.Clicked += () => { - var ofd = new OpenDialog ("Open Image", "Image"); - Application.Run (ofd); - - var path = ofd.FilePath.ToString (); - - if (string.IsNullOrWhiteSpace (path)) { - return; - } - - if(!File.Exists(path)) { - return; - } - - imageView.SetImage(Image.Load (File.ReadAllBytes (path))); - }; - } - - class ImageView : View { - - private Image fullResImage; - private Image matchSize; - - ConcurrentDictionary cache = new ConcurrentDictionary(); - - internal void SetImage (Image image) - { - fullResImage = image; - this.SetNeedsDisplay (); - } - - public override void Redraw (Rect bounds) - { - base.Redraw (bounds); - - if (fullResImage == null) { - return; - } - - // if we have not got a cached resized image of this size - if(matchSize == null || bounds.Width != matchSize.Width || bounds.Height != matchSize.Height) { - - // generate one - matchSize = fullResImage.Clone (x => x.Resize (bounds.Width, bounds.Height)); - } - - for (int y = 0; y < bounds.Height; y++) { - for (int x = 0; x < bounds.Width; x++) { - var rgb = matchSize [x, y]; - - var attr = cache.GetOrAdd (rgb, (rgb) => new Attribute (new TrueColor (), new TrueColor (rgb.R, rgb.G, rgb.B))); - - Driver.SetAttribute(attr); - AddRune (x, y, ' '); - } - } - } - } - } -} \ No newline at end of file diff --git a/UICatalog/UICatalog.csproj b/UICatalog/UICatalog.csproj index 84f0cdb07..4cc046017 100644 --- a/UICatalog/UICatalog.csproj +++ b/UICatalog/UICatalog.csproj @@ -18,6 +18,9 @@ TRACE;DEBUG_IDISPOSABLE + + +