diff --git a/BetterGenshinImpact/GameTask/AutoFishing/FishingTimePolicy.cs b/BetterGenshinImpact/GameTask/AutoFishing/FishingTimePolicy.cs index f85f5c72..539df3d3 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/FishingTimePolicy.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/FishingTimePolicy.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Text; +using System.ComponentModel; namespace BetterGenshinImpact.GameTask.AutoFishing { diff --git a/BetterGenshinImpact/GameTask/CaptureContent.cs b/BetterGenshinImpact/GameTask/CaptureContent.cs index c6da11f5..e7d644b5 100644 --- a/BetterGenshinImpact/GameTask/CaptureContent.cs +++ b/BetterGenshinImpact/GameTask/CaptureContent.cs @@ -1,6 +1,7 @@ using BetterGenshinImpact.GameTask.Model.Area; using System; using System.Drawing; +using Fischless.GameCapture; using OpenCvSharp; namespace BetterGenshinImpact.GameTask; @@ -19,7 +20,7 @@ public class CaptureContent : IDisposable public ImageRegion CaptureRectArea { get; private set; } - public CaptureContent(Mat image, int frameIndex, double interval) + public CaptureContent(CaptureImageRes image, int frameIndex, double interval) { FrameIndex = frameIndex; TimerInterval = interval; diff --git a/BetterGenshinImpact/GameTask/Common/TaskControl.cs b/BetterGenshinImpact/GameTask/Common/TaskControl.cs index 8ca354f2..0da826c8 100644 --- a/BetterGenshinImpact/GameTask/Common/TaskControl.cs +++ b/BetterGenshinImpact/GameTask/Common/TaskControl.cs @@ -17,13 +17,13 @@ public class TaskControl public static ILogger Logger { get; } = App.GetLogger(); public static readonly SemaphoreSlim TaskSemaphore = new(1, 1); - - + + public static void CheckAndSleep(int millisecondsTimeout) { TrySuspend(); CheckAndActivateGameWindow(); - + Thread.Sleep(millisecondsTimeout); } @@ -33,10 +33,10 @@ public class TaskControl { TrySuspend(); CheckAndActivateGameWindow(); - }, TimeSpan.FromSeconds(1), 100); Thread.Sleep(millisecondsTimeout); } + private static bool IsKeyPressed(User32.VK key) { // 获取按键状态 @@ -45,6 +45,7 @@ public class TaskControl // 检查高位是否为 1(表示按键被按下) return (state & 0x8000) != 0; } + public static void TrySuspend() { var first = true; @@ -65,6 +66,7 @@ public class TaskControl Simulation.SendInput.Keyboard.KeyUp(key); } } + Logger.LogWarning("快捷键触发暂停,等待解除"); foreach (var item in RunnerContext.Instance.SuspendableDictionary) { @@ -76,6 +78,7 @@ public class TaskControl Thread.Sleep(1000); } + //从暂停中解除 if (isSuspend) { @@ -97,12 +100,12 @@ public class TaskControl throw new RetryException("当前获取焦点的窗口不是原神"); } } - + var count = 0; //未激活则尝试恢复窗口 while (!SystemControl.IsGenshinImpactActiveByProcess()) { - if (count>=10 && count%10==0) + if (count >= 10 && count % 10 == 0) { Logger.LogInformation("多次尝试未恢复,尝试最小化后激活窗口!"); SystemControl.MinimizeAndActivateWindow(TaskContext.Instance().GameHandle); @@ -112,6 +115,7 @@ public class TaskControl Logger.LogInformation("当前获取焦点的窗口不是原神,尝试恢复窗口"); SystemControl.FocusWindow(TaskContext.Instance().GameHandle); } + count++; Thread.Sleep(1000); } @@ -135,10 +139,9 @@ public class TaskControl { throw new NormalEndException("取消自动任务"); } + TrySuspend(); CheckAndActivateGameWindow(); - - }, TimeSpan.FromSeconds(1), 100); Thread.Sleep(millisecondsTimeout); if (ct.IsCancellationRequested) @@ -165,9 +168,9 @@ public class TaskControl { throw new NormalEndException("取消自动任务"); } + TrySuspend(); CheckAndActivateGameWindow(); - }, TimeSpan.FromSeconds(1), 100); await Task.Delay(millisecondsTimeout, ct); if (ct is { IsCancellationRequested: true }) @@ -176,7 +179,7 @@ public class TaskControl } } - public static Mat CaptureGameImage(IGameCapture? gameCapture) + public static CaptureImageRes CaptureGameImage(IGameCapture? gameCapture) { var image = gameCapture?.Capture(); if (image == null) @@ -190,10 +193,10 @@ public class TaskControl { return image; } - + Sleep(30); } - + throw new Exception("尝试多次后,截图失败!"); } else @@ -201,8 +204,8 @@ public class TaskControl return image; } } - - public static Mat? CaptureGameImageNoRetry(IGameCapture? gameCapture) + + public static CaptureImageRes? CaptureGameImageNoRetry(IGameCapture? gameCapture) { return gameCapture?.Capture(); } @@ -213,8 +216,8 @@ public class TaskControl /// public static ImageRegion CaptureToRectArea(bool forceNew = false) { - var image =CaptureGameImage(TaskTriggerDispatcher.GlobalGameCapture); + var image = CaptureGameImage(TaskTriggerDispatcher.GlobalGameCapture); var content = new CaptureContent(image, 0, 0); return content.CaptureRectArea; } -} +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs b/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs index 1d2255cf..651460e2 100644 --- a/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs +++ b/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs @@ -3,6 +3,7 @@ using BetterGenshinImpact.GameTask.Model.Area.Converter; using BetterGenshinImpact.Helpers; using Fischless.WindowsInput; using System.Drawing; +using Fischless.GameCapture; using OpenCvSharp; namespace BetterGenshinImpact.GameTask.Model.Area; @@ -68,7 +69,7 @@ public class DesktopRegion : Region Simulation.SendInput.Mouse.MoveMouseBy((int)dx, (int)dy); } - public GameCaptureRegion Derive(Mat captureMat, int x, int y) + public GameCaptureRegion Derive(CaptureImageRes captureMat, int x, int y) { return new GameCaptureRegion(captureMat, x, y, this, new TranslationConverter(x, y)); } diff --git a/BetterGenshinImpact/GameTask/Model/Area/GameCaptureRegion.cs b/BetterGenshinImpact/GameTask/Model/Area/GameCaptureRegion.cs index 975b05df..5e4def3d 100644 --- a/BetterGenshinImpact/GameTask/Model/Area/GameCaptureRegion.cs +++ b/BetterGenshinImpact/GameTask/Model/Area/GameCaptureRegion.cs @@ -3,6 +3,7 @@ using BetterGenshinImpact.View.Drawable; using OpenCvSharp; using System; using System.Drawing; +using Fischless.GameCapture; using Size = OpenCvSharp.Size; namespace BetterGenshinImpact.GameTask.Model.Area; @@ -11,8 +12,19 @@ namespace BetterGenshinImpact.GameTask.Model.Area; /// 游戏捕获区域类 /// 主要用于转换到遮罩窗口的坐标 /// -public class GameCaptureRegion(Mat mat, int initX, int initY, Region? owner = null, INodeConverter? converter = null, DrawContent? drawContent = null) : ImageRegion(mat, initX, initY, owner, converter, drawContent) +public class GameCaptureRegion : ImageRegion { + public GameCaptureRegion(Mat mat, int initX, int initY, Region? owner = null, INodeConverter? converter = null, + DrawContent? drawContent = null) : base(mat, initX, initY, owner, converter, drawContent) + { + } + + public GameCaptureRegion(CaptureImageRes image, int initX, int initY, Region? owner = null, + INodeConverter? converter = null, DrawContent? drawContent = null) : base(image, initX, initY, owner, converter, drawContent) + { + } + + /// /// 在游戏捕获图像的坐标维度进行转换到遮罩窗口的坐标维度 /// @@ -48,6 +60,7 @@ public class GameCaptureRegion(Mat mat, int initX, int initY, Region? owner = nu { drawable.Pen = pen; } + return drawable; } @@ -66,6 +79,7 @@ public class GameCaptureRegion(Mat mat, int initX, int initY, Region? owner = nu { return this; } + var scale = Width / 1920d; var newMat = new Mat(); @@ -109,7 +123,7 @@ public class GameCaptureRegion(Mat mat, int initX, int initY, Region? owner = nu var (dx, dy) = deltaFunc(new Size(captureAreaRect.Width, captureAreaRect.Height), assetScale); DesktopRegion.DesktopRegionMoveBy(dx, dy); } - + /// /// 静态方法,输入1080P下的坐标,方法会自动转换到当前游戏捕获区域大小下的坐标并点击 /// @@ -126,4 +140,4 @@ public class GameCaptureRegion(Mat mat, int initX, int initY, Region? owner = nu // 1080P坐标 转换到实际游戏窗口坐标 GameRegionMove((_, scale) => (cx * scale, cy * scale)); } -} +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs b/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs index 44184919..b896e5ad 100644 --- a/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs +++ b/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text.RegularExpressions; +using Fischless.GameCapture; using Point = OpenCvSharp.Point; namespace BetterGenshinImpact.GameTask.Model.Area; @@ -77,6 +78,23 @@ public class ImageRegion : Region _srcMat = mat; } + public ImageRegion(CaptureImageRes image, int x, int y, Region? owner = null, INodeConverter? converter = null, + DrawContent? drawContent = null) : base(x, y, image.Width, image.Height, owner, converter, drawContent) + { + if (image.Bitmap != null) + { + _srcBitmap = image.Bitmap; + } + else if (image.Mat != null) + { + _srcMat = image.Mat; + } + else + { + throw new Exception("ImageRegion的构造函数参数错误"); + } + } + private bool HasImage() { return _srcBitmap != null || _srcMat != null; diff --git a/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs b/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs index 25a88f2f..4e9bcb02 100644 --- a/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs +++ b/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs @@ -386,19 +386,24 @@ namespace BetterGenshinImpact.GameTask Directory.CreateDirectory(path); } - var bitmap = TaskControl.CaptureGameImage(GameCapture); + var image = TaskControl.CaptureGameImage(GameCapture); + var mat = image.ForceGetMat(); + if (mat == null) + { + _logger.LogInformation("截图失败,未获取到图像"); + return; + } var name = $@"{DateTime.Now:yyyyMMddHHmmssffff}.png"; var savePath = Global.Absolute($@"log\screenshot\{name}"); - if (TaskContext.Instance().Config.CommonConfig.ScreenshotUidCoverEnabled) { var rect = TaskContext.Instance().Config.MaskWindowConfig.UidCoverRect; - bitmap.Rectangle(rect, Scalar.White, -1); - Cv2.ImWrite(savePath, bitmap); + mat.Rectangle(rect, Scalar.White, -1); + Cv2.ImWrite(savePath, mat); } else { - Cv2.ImWrite(savePath, bitmap); + Cv2.ImWrite(savePath, mat); } _logger.LogInformation("截图已保存: {Name}", name); diff --git a/BetterGenshinImpact/Helpers/Extensions/EnumExtensions.cs b/BetterGenshinImpact/Helpers/Extensions/EnumExtensions.cs new file mode 100644 index 00000000..64e61239 --- /dev/null +++ b/BetterGenshinImpact/Helpers/Extensions/EnumExtensions.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using BetterGenshinImpact.Model; + +namespace BetterGenshinImpact.Helpers.Extensions; + +public static class EnumExtensions +{ + public static string GetDescription(this Enum value) + { + return value.GetType() + .GetField(value.ToString()) + ?.GetCustomAttributes(typeof(DescriptionAttribute), false) + .Cast() + .FirstOrDefault() + ?.Description ?? value.ToString(); + } + + public static IEnumerable> ToEnumItems() where T : Enum + { + return Enum.GetValues(typeof(T)) + .Cast() + .Select(EnumItem.Create); + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/Model/EnumItem.cs b/BetterGenshinImpact/Model/EnumItem.cs new file mode 100644 index 00000000..43043a29 --- /dev/null +++ b/BetterGenshinImpact/Model/EnumItem.cs @@ -0,0 +1,21 @@ +using System; +using BetterGenshinImpact.Helpers.Extensions; + +namespace BetterGenshinImpact.Model; + +public class EnumItem where T : Enum +{ + public T Value { get; set; } + public string DisplayName { get; set; } + public string EnumName => Value.ToString(); + + // 提供一个静态工厂方法来创建实例 + public static EnumItem Create(T value) + { + return new EnumItem + { + Value = value, + DisplayName = value.GetDescription() // 使用扩展方法获取Description + }; + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/Service/Notification/NotificationService.cs b/BetterGenshinImpact/Service/Notification/NotificationService.cs index d3cefe84..47b0bd05 100644 --- a/BetterGenshinImpact/Service/Notification/NotificationService.cs +++ b/BetterGenshinImpact/Service/Notification/NotificationService.cs @@ -406,8 +406,19 @@ public class NotificationService : IHostedService, IDisposable try { - var bitmap = TaskControl.CaptureGameImageNoRetry(TaskTriggerDispatcher.GlobalGameCapture); - if (bitmap != null) notificationData.Screenshot = bitmap.ToBitmap(); + var image = TaskControl.CaptureGameImageNoRetry(TaskTriggerDispatcher.GlobalGameCapture); + + if (image != null) + { + if (image.Bitmap != null) + { + notificationData.Screenshot = image.Bitmap; + } + else if (image.Mat != null) + { + notificationData.Screenshot = image.Mat.ToBitmap(); + } + } } catch (Exception ex) { diff --git a/BetterGenshinImpact/View/CaptureTestWindow.xaml.cs b/BetterGenshinImpact/View/CaptureTestWindow.xaml.cs index 5ab0fdde..62d66548 100644 --- a/BetterGenshinImpact/View/CaptureTestWindow.xaml.cs +++ b/BetterGenshinImpact/View/CaptureTestWindow.xaml.cs @@ -61,11 +61,12 @@ public partial class CaptureTestWindow : Window { var sw = new Stopwatch(); sw.Start(); - var bitmap = _capture?.Capture(); + var image = _capture?.Capture(); sw.Stop(); Debug.WriteLine("截图耗时:" + sw.ElapsedMilliseconds); _captureTime += sw.ElapsedMilliseconds; + var bitmap = image?.ForceGetBitmap(); if (bitmap != null) { Debug.WriteLine($"Bitmap:{bitmap.Width}x{bitmap.Height}"); diff --git a/BetterGenshinImpact/View/Pages/HomePage.xaml b/BetterGenshinImpact/View/Pages/HomePage.xaml index d2c156a7..69fd21a6 100644 --- a/BetterGenshinImpact/View/Pages/HomePage.xaml +++ b/BetterGenshinImpact/View/Pages/HomePage.xaml @@ -134,14 +134,16 @@ + DisplayMemberPath="DisplayName" + SelectedValuePath="EnumName" + SelectedValue="{Binding Config.CaptureMode, Mode=TwoWay}"> diff --git a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs index dab44225..526d8015 100644 --- a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs @@ -15,22 +15,30 @@ using CommunityToolkit.Mvvm.Messaging.Messages; using Fischless.GameCapture; using Microsoft.Extensions.Logging; using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Net; +using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Interop; using Windows.System; +using BetterGenshinImpact.GameTask.AutoFishing; +using BetterGenshinImpact.Helpers.Extensions; +using BetterGenshinImpact.Model; using Wpf.Ui.Controls; namespace BetterGenshinImpact.ViewModel.Pages; public partial class HomePageViewModel : ViewModel { + [ObservableProperty] - private string[] _modeNames = GameCaptureFactory.ModeNames(); + private IEnumerable> _modeNames = EnumExtensions.ToEnumItems(); [ObservableProperty] private string? _selectedMode = CaptureModes.BitBlt.ToString(); @@ -66,11 +74,14 @@ public partial class HomePageViewModel : ViewModel Config = configService.Get(); ReadGameInstallPath(); + // WindowsGraphicsCapture 只支持 Win10 18362 及以上的版本 (Windows 10 version 1903 or later) // https://github.com/babalae/better-genshin-impact/issues/394 if (!OsVersionHelper.IsWindows10_1903_OrGreater) { - _modeNames = _modeNames.Where(x => x != CaptureModes.WindowsGraphicsCapture.ToString()).ToArray(); + // 删除 _modeNames 中的 CaptureModes.WindowsGraphicsCapture + _modeNames = _modeNames.Where(x => x.EnumName != CaptureModes.WindowsGraphicsCapture.ToString()).ToList(); + // DirectML 是在 Windows 10 版本 1903 和 Windows SDK 的相应版本中引入的。 // https://learn.microsoft.com/zh-cn/windows/ai/directml/dml _inferenceDeviceTypes = _inferenceDeviceTypes.Where(x => x != "GPU_DirectML").ToArray(); diff --git a/Fischless.GameCapture/BitBlt/BitBltCapture.cs b/Fischless.GameCapture/BitBlt/BitBltCapture.cs index 390ab91a..b1407cf0 100644 --- a/Fischless.GameCapture/BitBlt/BitBltCapture.cs +++ b/Fischless.GameCapture/BitBlt/BitBltCapture.cs @@ -18,7 +18,7 @@ public class BitBltCapture : IGameCapture public void Dispose() => Stop(); - public Mat? Capture() => Capture(false); + public CaptureImageRes? Capture() => Capture(false); public void Start(nint hWnd, Dictionary? settings = null) { @@ -111,7 +111,7 @@ public class BitBltCapture : IGameCapture /// /// 递归标志 /// 截图 - private Mat? Capture(bool recursive) + private CaptureImageRes? Capture(bool recursive) { if (_hWnd == IntPtr.Zero) { @@ -140,13 +140,13 @@ public class BitBltCapture : IGameCapture { // 成功截图 _lastCaptureFailed = false; - return result; + return CaptureImageRes.BuildNullable(result); } else if (result is null) { - if (_lastCaptureFailed) return result; // 这不是首次失败,不再进行尝试 + if (_lastCaptureFailed) return CaptureImageRes.BuildNullable(result); // 这不是首次失败,不再进行尝试 _lastCaptureFailed = true; // 设置失败标志 - if (recursive) return result; // 已设置递归标志,说明也不是首次失败 + if (recursive) return CaptureImageRes.BuildNullable(result); // 已设置递归标志,说明也不是首次失败 } } finally diff --git a/Fischless.GameCapture/BitBlt/BitBltOldCapture.cs b/Fischless.GameCapture/BitBlt/BitBltOldCapture.cs new file mode 100644 index 00000000..3f740a84 --- /dev/null +++ b/Fischless.GameCapture/BitBlt/BitBltOldCapture.cs @@ -0,0 +1,72 @@ +using System.Diagnostics; +using Vanara.PInvoke; + +namespace Fischless.GameCapture.BitBlt; + +public class BitBltOldCapture : IGameCapture +{ + private nint _hWnd; + + public CaptureModes Mode => CaptureModes.BitBltOld; + + public static object LockObject { get; } = new(); + + public bool IsCapturing { get; private set; } + + public void Dispose() => Stop(); + + public void Start(nint hWnd, Dictionary? settings = null) + { + _hWnd = hWnd; + IsCapturing = true; + if (settings != null && settings.TryGetValue("autoFixWin11BitBlt", out var value)) + { + if (value is true) + { + BitBltRegistryHelper.SetDirectXUserGlobalSettings(); + } + } + } + + public CaptureImageRes? Capture() + { + if (_hWnd == IntPtr.Zero) + { + return null; + } + + try + { + lock (LockObject) + { + User32.GetClientRect(_hWnd, out var windowRect); + int x = default, y = default; + var width = windowRect.right - windowRect.left; + var height = windowRect.bottom - windowRect.top; + + Bitmap bitmap = new(width, height); + using System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap); + var hdcDest = g.GetHdc(); + var hdcSrc = User32.GetDC(_hWnd == IntPtr.Zero ? User32.GetDesktopWindow() : _hWnd); + Gdi32.StretchBlt(hdcDest, 0, 0, width, height, hdcSrc, x, y, width, height, + Gdi32.RasterOperationMode.SRCCOPY); + g.ReleaseHdc(); + Gdi32.DeleteDC(hdcDest); + Gdi32.DeleteDC(hdcSrc); + return CaptureImageRes.BuildNullable(bitmap); + } + } + catch (Exception e) + { + Debug.WriteLine(e); + } + + return null!; + } + + public void Stop() + { + _hWnd = IntPtr.Zero; + IsCapturing = false; + } +} \ No newline at end of file diff --git a/Fischless.GameCapture/CaptureImageRes.cs b/Fischless.GameCapture/CaptureImageRes.cs new file mode 100644 index 00000000..412de1ce --- /dev/null +++ b/Fischless.GameCapture/CaptureImageRes.cs @@ -0,0 +1,76 @@ +using OpenCvSharp; +using OpenCvSharp.Extensions; + +namespace Fischless.GameCapture; + +/// +/// 捕获的图像 +/// +public class CaptureImageRes : IDisposable +{ + public Bitmap? Bitmap { get; set; } + public Mat? Mat { get; set; } + + public int Width => Mat?.Width ?? Bitmap?.Width ?? 0; + public int Height => Mat?.Height ?? Bitmap?.Height ?? 0; + + public CaptureImageRes(Mat mat) + { + Mat = mat; + } + + public CaptureImageRes(Bitmap bitmap) + { + Bitmap = bitmap; + } + + public static CaptureImageRes? BuildNullable(Bitmap? bitmap) + { + if (bitmap == null) + { + return null; + } + return new CaptureImageRes(bitmap); + } + + public static CaptureImageRes? BuildNullable(Mat? mat) + { + if (mat == null) + { + return null; + } + return new CaptureImageRes(mat); + } + + /// + /// 非特殊情况不要使用这个方法,会造成额外的性能消耗 + /// + /// + public Mat? ForceGetMat() + { + if (Mat == null) + { + Mat = Bitmap?.ToMat(); + } + return Mat; + } + + /// + /// 非特殊情况不要使用这个方法,会造成额外的性能消耗 + /// + /// + public Bitmap? ForceGetBitmap() + { + if (Bitmap == null) + { + Bitmap = Mat?.ToBitmap(); + } + return Bitmap; + } + + public void Dispose() + { + Bitmap?.Dispose(); + Mat?.Dispose(); + } +} \ No newline at end of file diff --git a/Fischless.GameCapture/CaptureModes.cs b/Fischless.GameCapture/CaptureModes.cs index c6c6834b..31b8cf65 100644 --- a/Fischless.GameCapture/CaptureModes.cs +++ b/Fischless.GameCapture/CaptureModes.cs @@ -1,8 +1,18 @@ -namespace Fischless.GameCapture; +using System.ComponentModel; + +namespace Fischless.GameCapture; public enum CaptureModes { + [Description("BitBlt(稳定)")] + BitBltOld, + + [Description("BitBlt(极速)")] BitBlt, + + [Description("WindowsGraphicsCapture")] WindowsGraphicsCapture, + + [Description("DwmGetDxSharedSurface")] DwmGetDxSharedSurface } diff --git a/Fischless.GameCapture/DwmSharedSurface/SharedSurfaceCapture.cs b/Fischless.GameCapture/DwmSharedSurface/SharedSurfaceCapture.cs index 53f2b6c8..27e4671d 100644 --- a/Fischless.GameCapture/DwmSharedSurface/SharedSurfaceCapture.cs +++ b/Fischless.GameCapture/DwmSharedSurface/SharedSurfaceCapture.cs @@ -67,7 +67,7 @@ namespace Fischless.GameCapture.DwmSharedSurface return region; } - public Mat? Capture() + public CaptureImageRes? Capture() { if (_hWnd == nint.Zero) { @@ -98,7 +98,7 @@ namespace Fischless.GameCapture.DwmSharedSurface } var bgrMat = new Mat(); Cv2.CvtColor(mat, bgrMat, ColorConversionCodes.BGRA2BGR); - return bgrMat; + return CaptureImageRes.BuildNullable(bgrMat); } } diff --git a/Fischless.GameCapture/GameCaptureFactory.cs b/Fischless.GameCapture/GameCaptureFactory.cs index 0bedc1d9..bb576e0f 100644 --- a/Fischless.GameCapture/GameCaptureFactory.cs +++ b/Fischless.GameCapture/GameCaptureFactory.cs @@ -12,6 +12,7 @@ public class GameCaptureFactory return mode switch { CaptureModes.BitBlt => new BitBlt.BitBltCapture(), + CaptureModes.BitBltOld => new BitBlt.BitBltOldCapture(), CaptureModes.WindowsGraphicsCapture => new Graphics.GraphicsCapture(), CaptureModes.DwmGetDxSharedSurface => new DwmSharedSurface.SharedSurfaceCapture(), _ => throw new ArgumentOutOfRangeException(nameof(mode), mode, null), diff --git a/Fischless.GameCapture/Graphics/GraphicsCapture.cs b/Fischless.GameCapture/Graphics/GraphicsCapture.cs index 5bfc3f5d..e1c94ca2 100644 --- a/Fischless.GameCapture/Graphics/GraphicsCapture.cs +++ b/Fischless.GameCapture/Graphics/GraphicsCapture.cs @@ -278,7 +278,7 @@ public class GraphicsCapture : IGameCapture return sdkMat; } - public Mat? Capture() + public CaptureImageRes? Capture() { // 使用读锁获取最新帧 _frameAccessLock.EnterReadLock(); @@ -291,7 +291,7 @@ public class GraphicsCapture : IGameCapture } // 返回最新帧的副本(这里我们必须克隆,因为Mat是不线程安全的) - return _latestFrame.Clone(); + return CaptureImageRes.BuildNullable(_latestFrame.Clone()); } finally { diff --git a/Fischless.GameCapture/IGameCapture.cs b/Fischless.GameCapture/IGameCapture.cs index ffb85923..38fe1564 100644 --- a/Fischless.GameCapture/IGameCapture.cs +++ b/Fischless.GameCapture/IGameCapture.cs @@ -9,7 +9,7 @@ public interface IGameCapture : IDisposable public void Start(nint hWnd, Dictionary? settings = null); - public Mat? Capture(); + public CaptureImageRes? Capture(); public void Stop(); }