using System; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Threading; using SixLabors.ImageSharp.PixelFormats; using ImpromptuNinjas.UltralightSharp.Enums; namespace ImpromptuNinjas.UltralightSharp.Demo { public static partial class DemoProgram { public static void Main(string[] args) { var isNotInteractive = !Environment.UserInteractive || Console.IsInputRedirected; // setup logging Safe.LoggerLogMessageCallback cb = LoggerCallback; Safe.Ultralight.SetLogger(new Safe.Logger {LogMessage = cb}); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Console.OutputEncoding = Encoding.UTF8; Ansi.WindowsConsole.TryEnableVirtualTerminalProcessing(); } var asmPath = new Uri(typeof(DemoProgram).Assembly.CodeBase!).LocalPath; var asmDir = Path.GetDirectoryName(asmPath)!; var tempDir = Path.GetTempPath(); // find a place to stash instance storage string storagePath; do storagePath = Path.Combine(tempDir, Guid.NewGuid().ToString()); while (Directory.Exists(storagePath) || File.Exists(storagePath)); { using var cfg = new Safe.Config(); var cachePath = Path.Combine(storagePath, "Cache"); cfg.SetCachePath(cachePath); var resourcePath = Path.Combine(asmDir, "resources"); cfg.SetResourcePath(resourcePath); cfg.SetUseGpuRenderer(false); cfg.SetEnableImages(true); cfg.SetEnableJavaScript(true); Safe.AppCore.EnablePlatformFontLoader(); { var assetsPath = Path.Combine(asmDir, "assets"); Safe.AppCore.EnablePlatformFileSystem(assetsPath); } using var renderer = new Safe.Renderer(cfg); var sessionName = "Demo"; using var session = new Safe.Session(renderer, false, sessionName); using var view = new Safe.View(renderer, 640, 480, false, session); //var htmlString = "Loading..."; //Console.WriteLine($"Loading HTML: {htmlString}"); //view.LoadHtml(htmlString); view.LoadUrl("file:///index.html"); var nextStep = false; view.SetFinishLoadingCallback((data, caller, frameId, isMainFrame, url) => { //Console.WriteLine($"Loading Finished, URL: {url}"); nextStep = true; }, default); if (isNotInteractive) do { renderer.Update(); renderer.Render(); } while (nextStep == false); const double wm = 4; const double hm = wm * 2; GetConsoleSize(out var cw, out var ch); view.Resize((uint) (cw * wm), (uint) (ch * hm)); var ditherIndex = 0; var customDither = Dithers[ditherIndex]; var ansiColors = (AnsiColors) 0; var step = 0; var escInstrBytes = Encoding.UTF8.GetBytes("Press C to change color mode, D to change dither mode, ESC to exit."); var key = new ConsoleKeyInfo(); //Console.TreatControlCAsInput = true; using var stdOut = Console.OpenStandardOutput(256); using var o = new BufferedStream(stdOut, 8 * 1024 * 1024); byte[]? urlStrBytes = null; // alt buffer if (!isNotInteractive) { o.WriteByte(0x1B); o.WriteByte((byte) '['); o.WriteByte((byte) '1'); o.WriteByte((byte) '0'); o.WriteByte((byte) '4'); o.WriteByte((byte) '9'); o.WriteByte((byte) 'h'); o.Flush(); } try { Console.CursorVisible = false; } catch { /* ok */ } try { Console.Clear(); } catch { /* ok */ } try { Console.SetCursorPosition(0, 0); } catch { o.WriteByte(0x1B); o.WriteByte((byte) '7'); } do { GetConsoleSize(out var newCw, out var newCh); if (cw != newCw || ch != newCh) { cw = newCw; ch = newCh; try { Console.Clear(); } catch { /* ok */ } view.Resize((uint) (cw * wm), (uint) (ch * hm)); } try { Console.SetCursorPosition(0, 0); } catch { o.WriteByte(0x1B); o.WriteByte((byte) '8'); } var urlStr = view.GetUrl(); var urlStrSize = Encoding.UTF8.GetByteCount(urlStr ?? ""); if (urlStrBytes == null || urlStrBytes.Length < urlStrSize) urlStrBytes = new byte[urlStrSize]; var urlStrBytesLen = Encoding.UTF8.GetBytes(urlStr, urlStrBytes); o.Write(urlStrBytes, 0, urlStrBytesLen); o.WriteByte((byte) '\n'); renderer.Update(); renderer.Render(); var surface = view.GetSurface(); var bitmap = surface.GetBitmap(); var pixels = bitmap.LockPixels(); RenderAnsi(o, pixels, bitmap.GetWidth(), bitmap.GetHeight(), 2, borderless: true, colors: ansiColors, // isNotInteractive customDither: customDither ); bitmap.UnlockPixels(); if (isNotInteractive) return; o.Write(escInstrBytes); o.Flush(); if (nextStep) switch (step) { case 0: { view.EvaluateScript("rotateBgColor()"); nextStep = false; ++step; // ReSharper disable once ObjectCreationAsStatement new Timer(state => { nextStep = true; }, null, 10000, Timeout.Infinite); break; } case 1: { var urlString = "https://cristurm.github.io/nyan-cat/"; view.LoadUrl(urlString); nextStep = false; ++step; break; } case 2: view.EvaluateScript( "const m = document.createElement('marquee');" + "const d = document.createElement('div');" + "document.body.appendChild(d);" + "d.appendChild(m);" + "m.setAttribute('width', '100%');" + "m.setAttribute('scrollamount', 4);" + "m.setAttribute('scrolldelay', 1);" + "m.setAttribute('truespeed', 1);" + "m.innerText = 'UltralightSharp';" + "m.style.cssText = '" + "position: absolute;" + "bottom: 0;" + "left: 0;" + "z-index: 999;" + "padding: 4px 8px;" + "font-size: 2.5em;" + "font-weight: bold;" + "width: 100vw;" + "color: #fff" + "';"); nextStep = false; ++step; break; } if (!Console.KeyAvailable) continue; key = Console.ReadKey(true); Console.WriteLine(); if (key.Key == ConsoleKey.D) { ditherIndex = (ditherIndex + 1) % Dithers.Length; customDither = Dithers[ditherIndex]; continue; } if (key.Key == ConsoleKey.C) { ansiColors = (AnsiColors) (((int) ansiColors + 1) % 3); continue; } } while (key.Key != ConsoleKey.Escape); } try { Directory.Delete(storagePath, true); } catch { /* ok */ } } private static void LoggerCallback(LogLevel logLevel, string? msg) { Debug.WriteLine($"{logLevel.ToString()}: {msg}"); } } }