Browse Source

Investigate changing sixel to output as part of view render

tznind 10 months ago
parent
commit
519d8c0fcd
1 changed files with 119 additions and 101 deletions
  1. 119 101
      UICatalog/Scenarios/Images.cs

+ 119 - 101
UICatalog/Scenarios/Images.cs

@@ -20,6 +20,8 @@ namespace UICatalog.Scenarios;
 public class Images : Scenario
 {
     private ImageView _imageView;
+    private Point _screenLocationForSixel;
+    private string _encodedSixelData;
 
     public override void Main ()
     {
@@ -195,27 +197,134 @@ public class Images : Scenario
         tabSixel.View.Add (lblPxY);
         tabSixel.View.Add (pxY);
 
+        sixelView.DrawContent += SixelViewOnDrawContent;
+
+
         btnSixel.Accept += (s, e) =>
                            {
-                               _imageView.OutputSixel (
-                                                       sixelView.FrameToScreen ().Location,
-                                                       sixelView.Frame.Size,
-                                                       pxX.Value,
-                                                       pxY.Value);
+
+                               if (_imageView.FullResImage == null)
+                               {
+                                   return;
+                               }
+
+
+                               _screenLocationForSixel = sixelView.FrameToScreen ().Location;
+                               _encodedSixelData = GenerateSixelData(
+                                                               _imageView.FullResImage,
+                                                               sixelView.Frame.Size,
+                                                               pxX.Value,
+                                                               pxY.Value);
                            };
     }
+    void SixelViewOnDrawContent (object sender, DrawEventArgs e)
+    {
+        if (!string.IsNullOrWhiteSpace (_encodedSixelData))
+        {
+            // Does not work
+            Application.Driver?.Move (_screenLocationForSixel.X, _screenLocationForSixel.Y);
+            Application.Driver?.AddStr (_encodedSixelData);
+
+            // Works in NetDriver but results in screen flicker when moving mouse but vanish instantly
+            // Console.SetCursorPosition (_screenLocationForSixel.X, _screenLocationForSixel.Y);
+            // Console.Write (_encodedSixelData);
+        }
+    }
+
+    public string GenerateSixelData(
+            Image<Rgba32> fullResImage,
+            Size maxSize,
+            int pixelsPerCellX,
+            int pixelsPerCellY
+        )
+    {
+        var encoder = new SixelEncoder ();
+
+        // Calculate the target size in pixels based on console units
+        int targetWidthInPixels = maxSize.Width * pixelsPerCellX;
+        int targetHeightInPixels = maxSize.Height * pixelsPerCellY;
+
+        // Get the original image dimensions
+        int originalWidth = fullResImage.Width;
+        int originalHeight = fullResImage.Height;
+
+        // Use the helper function to get the resized dimensions while maintaining the aspect ratio
+        Size newSize = CalculateAspectRatioFit (originalWidth, originalHeight, targetWidthInPixels, targetHeightInPixels);
+
+        // Resize the image to match the console size
+        Image<Rgba32> resizedImage = fullResImage.Clone (x => x.Resize (newSize.Width, newSize.Height));
+
+        string encoded = encoder.EncodeSixel (ConvertToColorArray (resizedImage));
+
+        var pv = new PaletteView (encoder.Quantizer.Palette.ToList ());
+
+        var dlg = new Dialog
+        {
+            Title = "Palette (Esc to close)",
+            Width = Dim.Fill (2),
+            Height = Dim.Fill (1)
+        };
+
+        var btn = new Button
+        {
+            Text = "Ok"
+        };
+
+        btn.Accept += (s, e) => Application.RequestStop ();
+        dlg.Add (pv);
+        dlg.AddButton (btn);
+        Application.Run (dlg);
+
+        return encoded;
+    }
+
+    private Size CalculateAspectRatioFit (int originalWidth, int originalHeight, int targetWidth, int targetHeight)
+    {
+        // Calculate the scaling factor for width and height
+        double widthScale = (double)targetWidth / originalWidth;
+        double heightScale = (double)targetHeight / originalHeight;
+
+        // Use the smaller scaling factor to maintain the aspect ratio
+        double scale = Math.Min (widthScale, heightScale);
+
+        // Calculate the new width and height while keeping the aspect ratio
+        var newWidth = (int)(originalWidth * scale);
+        var newHeight = (int)(originalHeight * scale);
+
+        // Return the new size as a Size object
+        return new (newWidth, newHeight);
+    }
+
+    public static Color [,] ConvertToColorArray (Image<Rgba32> image)
+    {
+        int width = image.Width;
+        int height = image.Height;
+        Color [,] colors = new Color [width, height];
+
+        // Loop through each pixel and convert Rgba32 to Terminal.Gui color
+        for (var x = 0; x < width; x++)
+        {
+            for (var y = 0; y < height; y++)
+            {
+                Rgba32 pixel = image [x, y];
+                colors [x, y] = new (pixel.R, pixel.G, pixel.B); // Convert Rgba32 to Terminal.Gui color
+            }
+        }
+
+        return colors;
+    }
 
     private class ImageView : View
     {
         private readonly ConcurrentDictionary<Rgba32, Attribute> _cache = new ();
-        private Image<Rgba32> _fullResImage;
+        public Image<Rgba32> FullResImage;
         private Image<Rgba32> _matchSize;
 
         public override void OnDrawContent (Rectangle bounds)
         {
             base.OnDrawContent (bounds);
 
-            if (_fullResImage == null)
+            if (FullResImage == null)
             {
                 return;
             }
@@ -224,7 +333,7 @@ public class Images : Scenario
             if (_matchSize == null || bounds.Width != _matchSize.Width || bounds.Height != _matchSize.Height)
             {
                 // generate one
-                _matchSize = _fullResImage.Clone (x => x.Resize (bounds.Width, bounds.Height));
+                _matchSize = FullResImage.Clone (x => x.Resize (bounds.Width, bounds.Height));
             }
 
             for (var y = 0; y < bounds.Height; y++)
@@ -249,102 +358,11 @@ public class Images : Scenario
 
         internal void SetImage (Image<Rgba32> image)
         {
-            _fullResImage = image;
+            FullResImage = image;
             SetNeedsDisplay ();
         }
 
-        public void OutputSixel (
-            Point screenPosition,
-            Size maxSize,
-            int pixelsPerCellX,
-            int pixelsPerCellY
-        )
-        {
-            if (_fullResImage == null)
-            {
-                return;
-            }
-
-            var encoder = new SixelEncoder ();
-
-            // Calculate the target size in pixels based on console units
-            int targetWidthInPixels = maxSize.Width * pixelsPerCellX;
-            int targetHeightInPixels = maxSize.Height * pixelsPerCellY;
-
-            // Get the original image dimensions
-            int originalWidth = _fullResImage.Width;
-            int originalHeight = _fullResImage.Height;
-
-            // Use the helper function to get the resized dimensions while maintaining the aspect ratio
-            Size newSize = CalculateAspectRatioFit (originalWidth, originalHeight, targetWidthInPixels, targetHeightInPixels);
-
-            // Resize the image to match the console size
-            Image<Rgba32> resizedImage = _fullResImage.Clone (x => x.Resize (newSize.Width, newSize.Height));
-
-            string encoded = encoder.EncodeSixel (ConvertToColorArray (resizedImage));
-
-            var pv = new PaletteView (encoder.Quantizer.Palette.ToList ());
-
-            var dlg = new Dialog
-            {
-                Title = "Palette (Esc to close)",
-                Width = Dim.Fill (2),
-                Height = Dim.Fill (1)
-            };
-
-            var btn = new Button
-            {
-                Text = "Ok"
-            };
-
-            btn.Accept += (s, e) => Application.RequestStop ();
-            dlg.Add (pv);
-            dlg.AddButton (btn);
-            Application.Run (dlg);
-
-            Application.Sixel.Add (
-                                   new()
-                                   {
-                                       ScreenPosition = screenPosition,
-                                       SixelData = encoded
-                                   });
-        }
-
-        private Size CalculateAspectRatioFit (int originalWidth, int originalHeight, int targetWidth, int targetHeight)
-        {
-            // Calculate the scaling factor for width and height
-            double widthScale = (double)targetWidth / originalWidth;
-            double heightScale = (double)targetHeight / originalHeight;
-
-            // Use the smaller scaling factor to maintain the aspect ratio
-            double scale = Math.Min (widthScale, heightScale);
-
-            // Calculate the new width and height while keeping the aspect ratio
-            var newWidth = (int)(originalWidth * scale);
-            var newHeight = (int)(originalHeight * scale);
-
-            // Return the new size as a Size object
-            return new (newWidth, newHeight);
-        }
-
-        public static Color [,] ConvertToColorArray (Image<Rgba32> image)
-        {
-            int width = image.Width;
-            int height = image.Height;
-            Color [,] colors = new Color [width, height];
-
-            // Loop through each pixel and convert Rgba32 to Terminal.Gui color
-            for (var x = 0; x < width; x++)
-            {
-                for (var y = 0; y < height; y++)
-                {
-                    Rgba32 pixel = image [x, y];
-                    colors [x, y] = new (pixel.R, pixel.G, pixel.B); // Convert Rgba32 to Terminal.Gui color
-                }
-            }
-
-            return colors;
-        }
+        
     }
 
     public class PaletteView : View