mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-05-05 11:34:07 +02:00
Rewrite screenshot functionality using new DevTools API
This commit is contained in:
parent
5ebfc67e48
commit
a8e7f065cf
Browser/Notification/Screenshot
Utils
@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using System.Threading.Tasks;
|
||||
using CefSharp;
|
||||
using CefSharp.DevTools.Page;
|
||||
using TweetDuck.Browser.Adapters;
|
||||
using TweetDuck.Controls;
|
||||
using TweetDuck.Dialogs;
|
||||
@ -54,40 +54,38 @@ private void SetScreenshotHeight(int browserHeight) {
|
||||
this.height = BrowserUtils.Scale(browserHeight, SizeScale);
|
||||
}
|
||||
|
||||
public bool TakeScreenshot(bool ignoreHeightError = false) {
|
||||
public Task<Image> TakeScreenshot(bool ignoreHeightError = false) {
|
||||
if (!ignoreHeightError) {
|
||||
if (height == 0) {
|
||||
FormMessage.Error("Screenshot Failed", "Could not detect screenshot size.", FormMessage.OK);
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
else if (height > ClientSize.Height) {
|
||||
FormMessage.Error("Screenshot Failed", $"Screenshot is too large: {height}px > {ClientSize.Height}px", FormMessage.OK);
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!WindowsUtils.IsAeroEnabled) {
|
||||
MoveToVisibleLocation(); // TODO make this look nicer I guess
|
||||
return Task.Run(TakeScreenshotImpl);
|
||||
}
|
||||
|
||||
private async Task<Image> TakeScreenshotImpl() {
|
||||
if (this.height == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
IntPtr context = NativeMethods.GetDC(this.Handle);
|
||||
Viewport viewport = new Viewport {
|
||||
Width = this.ClientSize.Width,
|
||||
Height = this.height,
|
||||
Scale = 1
|
||||
};
|
||||
|
||||
if (context == IntPtr.Zero) {
|
||||
FormMessage.Error("Screenshot Failed", "Could not retrieve a graphics context handle for the notification window to take the screenshot.", FormMessage.OK);
|
||||
return false;
|
||||
byte[] data;
|
||||
using (var devToolsClient = browser.GetDevToolsClient()) {
|
||||
data = (await devToolsClient.Page.CaptureScreenshotAsync(CaptureScreenshotFormat.Png, clip: viewport)).Data;
|
||||
}
|
||||
else {
|
||||
using Bitmap bmp = new Bitmap(ClientSize.Width, Math.Max(1, height), PixelFormat.Format32bppRgb);
|
||||
|
||||
try {
|
||||
NativeMethods.RenderSourceIntoBitmap(context, bmp);
|
||||
} finally {
|
||||
NativeMethods.ReleaseDC(this.Handle, context);
|
||||
}
|
||||
|
||||
Clipboard.SetImage(bmp);
|
||||
return true;
|
||||
}
|
||||
return Image.FromStream(new MemoryStream(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,13 +7,15 @@
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using TweetDuck.Controls;
|
||||
using TweetLib.Core.Features.Plugins;
|
||||
#if GEN_SCREENSHOT_FRAMES
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using TweetDuck.Core.Utils;
|
||||
using TweetDuck.Utils;
|
||||
#endif
|
||||
|
||||
namespace TweetDuck.Browser.Notification.Screenshot {
|
||||
@ -45,7 +47,7 @@ public TweetScreenshotManager(FormBrowser owner, PluginManager pluginManager) {
|
||||
this.disposer.Tick += disposer_Tick;
|
||||
|
||||
#if GEN_SCREENSHOT_FRAMES
|
||||
this.debugger = new Timer{ Interval = 16 };
|
||||
this.debugger = new Timer { Interval = 16 };
|
||||
this.debugger.Tick += debugger_Tick;
|
||||
#endif
|
||||
}
|
||||
@ -85,14 +87,22 @@ private void Callback() {
|
||||
}
|
||||
|
||||
timeout.Stop();
|
||||
screenshot.TakeScreenshot();
|
||||
screenshot.TakeScreenshot().ContinueWith(HandleResult, TaskScheduler.FromCurrentSynchronizationContext());
|
||||
}
|
||||
|
||||
#if !NO_HIDE_SCREENSHOTS
|
||||
OnFinished();
|
||||
#else
|
||||
screenshot.MoveToVisibleLocation();
|
||||
screenshot.FormClosed += (sender, args) => disposer.Start();
|
||||
#endif
|
||||
private void HandleResult(Task<Image> task) {
|
||||
if (task.IsFaulted) {
|
||||
Program.Reporter.HandleException("Screenshot Failed", "An error occurred while taking a screenshot.", true, task.Exception!.InnerException);
|
||||
}
|
||||
else if (task.IsCompleted) {
|
||||
Clipboard.SetImage(task.Result);
|
||||
#if !NO_HIDE_SCREENSHOTS
|
||||
OnFinished();
|
||||
#else
|
||||
screenshot.MoveToVisibleLocation();
|
||||
screenshot.FormClosed += (sender, args) => disposer.Start();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFinished() {
|
||||
@ -118,30 +128,36 @@ public void Dispose() {
|
||||
#if GEN_SCREENSHOT_FRAMES
|
||||
private static readonly string DebugScreenshotPath = Path.Combine(Program.StoragePath, "TD_Screenshots");
|
||||
|
||||
private void StartDebugger(){
|
||||
private void StartDebugger() {
|
||||
frameCounter = 0;
|
||||
|
||||
try{
|
||||
try {
|
||||
Directory.Delete(DebugScreenshotPath, true);
|
||||
WindowsUtils.TrySleepUntil(() => !Directory.Exists(DebugScreenshotPath), 1000, 10);
|
||||
}catch(DirectoryNotFoundException){}
|
||||
} catch (DirectoryNotFoundException) {}
|
||||
|
||||
Directory.CreateDirectory(DebugScreenshotPath);
|
||||
debugger.Start();
|
||||
}
|
||||
|
||||
private void debugger_Tick(object sender, EventArgs e){
|
||||
if (frameCounter < 63 && screenshot.TakeScreenshot(true)){
|
||||
try{
|
||||
Clipboard.GetImage()?.Save(Path.Combine(DebugScreenshotPath, "frame_" + (++frameCounter) + ".png"), ImageFormat.Png);
|
||||
}catch{
|
||||
System.Diagnostics.Debug.WriteLine("Failed generating frame " + frameCounter);
|
||||
}
|
||||
private void debugger_Tick(object sender, EventArgs e) {
|
||||
if (frameCounter < 63) {
|
||||
int frame = ++frameCounter;
|
||||
screenshot.TakeScreenshot(true).ContinueWith(task => SaveDebugFrame(task, frame), TaskScheduler.FromCurrentSynchronizationContext());
|
||||
}
|
||||
else{
|
||||
else {
|
||||
debugger.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private static void SaveDebugFrame(Task<Image> task, int frame) {
|
||||
if (task.IsFaulted) {
|
||||
System.Diagnostics.Debug.WriteLine("Failed generating frame " + frame + ": " + task.Exception!.InnerException);
|
||||
}
|
||||
else if (task.IsCompleted) {
|
||||
task.Result?.Save(Path.Combine(DebugScreenshotPath, "frame_" + (++frame) + ".png"), ImageFormat.Png);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
@ -68,19 +67,6 @@ private struct MSLLHOOKSTRUCT {
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetLastInputInfo(ref LASTINPUTINFO info);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr GetDC(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
|
||||
|
||||
[DllImport("dwmapi.dll")]
|
||||
public static extern int DwmIsCompositionEnabled(out bool enabled);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);
|
||||
@ -139,16 +125,5 @@ public static int GetIdleSeconds() {
|
||||
int seconds = (int) Math.Floor(TimeSpan.FromMilliseconds(ticks - info.dwTime).TotalSeconds);
|
||||
return Math.Max(0, seconds); // ignore rollover after several weeks of uptime
|
||||
}
|
||||
|
||||
public static void RenderSourceIntoBitmap(IntPtr source, Bitmap target) {
|
||||
using Graphics graphics = Graphics.FromImage(target);
|
||||
IntPtr graphicsHandle = graphics.GetHdc();
|
||||
|
||||
try {
|
||||
BitBlt(graphicsHandle, 0, 0, target.Width, target.Height, source, 0, 0, 0x00CC0020);
|
||||
} finally {
|
||||
graphics.ReleaseHdc(graphicsHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,10 +6,7 @@
|
||||
|
||||
namespace TweetDuck.Utils {
|
||||
static class WindowsUtils {
|
||||
private static readonly bool IsWindows8OrNewer = OSVersionEquals(major: 6, minor: 2); // windows 8/10
|
||||
|
||||
public static bool ShouldAvoidToolWindow { get; } = IsWindows8OrNewer;
|
||||
public static bool IsAeroEnabled => IsWindows8OrNewer || (NativeMethods.DwmIsCompositionEnabled(out bool isCompositionEnabled) == 0 && isCompositionEnabled);
|
||||
public static bool ShouldAvoidToolWindow { get; } = OSVersionEquals(major: 6, minor: 2); // windows 8/10
|
||||
|
||||
private static bool OSVersionEquals(int major, int minor) {
|
||||
System.Version ver = Environment.OSVersion.Version;
|
||||
|
Loading…
Reference in New Issue
Block a user