Images.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.IO;
  4. using System.Text;
  5. using SixLabors.ImageSharp;
  6. using SixLabors.ImageSharp.PixelFormats;
  7. using SixLabors.ImageSharp.Processing;
  8. using Terminal.Gui;
  9. using Color = Terminal.Gui.Color;
  10. namespace UICatalog.Scenarios;
  11. [ScenarioMetadata ("Images", "Demonstration of how to render an image with/without true color support.")]
  12. [ScenarioCategory ("Colors")]
  13. [ScenarioCategory ("Drawing")]
  14. public class Images : Scenario
  15. {
  16. public override void Main ()
  17. {
  18. Application.Init ();
  19. var win = new Window { Title = $"{Application.QuitKey} to Quit - Scenario: {GetName()}" };
  20. bool canTrueColor = Application.Driver?.SupportsTrueColor ?? false;
  21. var lblDriverName = new Label { X = 0, Y = 0, Text = $"Driver is {Application.Driver?.GetType ().Name}" };
  22. win.Add (lblDriverName);
  23. var cbSupportsTrueColor = new CheckBox
  24. {
  25. X = Pos.Right (lblDriverName) + 2,
  26. Y = 0,
  27. CheckedState = canTrueColor ? CheckState.Checked : CheckState.UnChecked,
  28. CanFocus = false,
  29. Text = "supports true color "
  30. };
  31. win.Add (cbSupportsTrueColor);
  32. var cbUseTrueColor = new CheckBox
  33. {
  34. X = Pos.Right (cbSupportsTrueColor) + 2,
  35. Y = 0,
  36. CheckedState = !Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
  37. Enabled = canTrueColor,
  38. Text = "Use true color"
  39. };
  40. cbUseTrueColor.CheckedStateChanging += (_, evt) => Application.Force16Colors = evt.NewValue == CheckState.UnChecked;
  41. win.Add (cbUseTrueColor);
  42. var btnOpenImage = new Button { X = Pos.Right (cbUseTrueColor) + 2, Y = 0, Text = "Open Image" };
  43. win.Add (btnOpenImage);
  44. var imageView = new ImageView
  45. {
  46. X = 0, Y = Pos.Bottom (lblDriverName), Width = Dim.Fill (), Height = Dim.Fill ()
  47. };
  48. win.Add (imageView);
  49. btnOpenImage.Accepted += (_, _) =>
  50. {
  51. var ofd = new OpenDialog { Title = "Open Image", AllowsMultipleSelection = false };
  52. Application.Run (ofd);
  53. if (ofd.Path is { })
  54. {
  55. Directory.SetCurrentDirectory (Path.GetFullPath (Path.GetDirectoryName (ofd.Path)!));
  56. }
  57. if (ofd.Canceled)
  58. {
  59. ofd.Dispose ();
  60. return;
  61. }
  62. string path = ofd.FilePaths [0];
  63. ofd.Dispose ();
  64. if (string.IsNullOrWhiteSpace (path))
  65. {
  66. return;
  67. }
  68. if (!File.Exists (path))
  69. {
  70. return;
  71. }
  72. Image<Rgba32> img;
  73. try
  74. {
  75. img = Image.Load<Rgba32> (File.ReadAllBytes (path));
  76. }
  77. catch (Exception ex)
  78. {
  79. MessageBox.ErrorQuery ("Could not open file", ex.Message, "Ok");
  80. return;
  81. }
  82. imageView.SetImage (img);
  83. Application.Refresh ();
  84. };
  85. Application.Run (win);
  86. win.Dispose ();
  87. Application.Shutdown ();
  88. }
  89. private class ImageView : View
  90. {
  91. private readonly ConcurrentDictionary<Rgba32, Attribute> _cache = new ();
  92. private Image<Rgba32> _fullResImage;
  93. private Image<Rgba32> _matchSize;
  94. public override void OnDrawContent (Rectangle bounds)
  95. {
  96. base.OnDrawContent (bounds);
  97. if (_fullResImage == null)
  98. {
  99. return;
  100. }
  101. // if we have not got a cached resized image of this size
  102. if (_matchSize == null || bounds.Width != _matchSize.Width || bounds.Height != _matchSize.Height)
  103. {
  104. // generate one
  105. _matchSize = _fullResImage.Clone (x => x.Resize (bounds.Width, bounds.Height));
  106. }
  107. for (var y = 0; y < bounds.Height; y++)
  108. {
  109. for (var x = 0; x < bounds.Width; x++)
  110. {
  111. Rgba32 rgb = _matchSize [x, y];
  112. Attribute attr = _cache.GetOrAdd (
  113. rgb,
  114. rgb => new Attribute (
  115. new Color (),
  116. new Color (rgb.R, rgb.G, rgb.B)
  117. )
  118. );
  119. Driver.SetAttribute (attr);
  120. AddRune (x, y, (Rune)' ');
  121. }
  122. }
  123. }
  124. internal void SetImage (Image<Rgba32> image)
  125. {
  126. _fullResImage = image;
  127. SetNeedsDisplay ();
  128. }
  129. }
  130. }