Skip to content

Commit 0bea2d0

Browse files
shatyukahuiyadanli
andauthored
截图优化 (#1480)
* BitBlt 优化 * BitBlt恢复Top-down * 渲染时翻转图像 * CaptureSession引用计数 * 恢复成无拷贝Mat * 合法性检查 * 优化截图预览窗口 * 保存截图文件必要时需要克隆一份Mat * BitBlt内存池 * 返回拷贝就不用对Session做引用计数了 * 移除CaptureImageRes * 优化DirectX * 更好地处理padding * BitBlt去掉padding 1920*1080的游戏窗口是4字节对齐的,因此不会有性能影响。这里主要用于测试。 * 修复修改窗口大小 * 合并CreateStagingTexture * 修复设备丢失崩溃 * WGC截图支持HDR * fix typo * CodeQA * 去掉1px窗口边框 * DirectX截图去掉A通道 * HDR转换使用GPU加速 --------- Co-authored-by: 辉鸭蛋 <huiyadanli@gmail.com>
1 parent 5b3bac4 commit 0bea2d0

29 files changed

+652
-741
lines changed

BetterGenshinImpact/GameTask/AutoFishing/BehaviourTreeExtensions.cs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@ public virtual void SaveScreenshot(ImageRegion imageRegion, string? name)
166166
Directory.CreateDirectory(path);
167167
}
168168

169-
var bitmap = imageRegion.SrcBitmap;
170169
if (String.IsNullOrWhiteSpace(name))
171170
{
172171
name = $@"{DateTime.Now:yyyyMMddHHmmssffff}.png";
@@ -176,17 +175,25 @@ public virtual void SaveScreenshot(ImageRegion imageRegion, string? name)
176175
var mat = imageRegion.SrcMat;
177176
if (TaskContext.Instance().Config.CommonConfig.ScreenshotUidCoverEnabled)
178177
{
179-
var assetScale = TaskContext.Instance().SystemInfo.ScaleTo1080PRatio;
180-
var rect = new Rect((int)(mat.Width - MaskWindowConfig.UidCoverRightBottomRect.X * assetScale),
181-
(int)(mat.Height - MaskWindowConfig.UidCoverRightBottomRect.Y * assetScale),
182-
(int)(MaskWindowConfig.UidCoverRightBottomRect.Width * assetScale),
183-
(int)(MaskWindowConfig.UidCoverRightBottomRect.Height * assetScale));
184-
mat.Rectangle(rect, Scalar.White, -1);
178+
new Task(() =>
179+
{
180+
using var mat2 = mat.Clone();
181+
var assetScale = TaskContext.Instance().SystemInfo.ScaleTo1080PRatio;
182+
var rect = new Rect((int)(mat.Width - MaskWindowConfig.UidCoverRightBottomRect.X * assetScale),
183+
(int)(mat.Height - MaskWindowConfig.UidCoverRightBottomRect.Y * assetScale),
184+
(int)(MaskWindowConfig.UidCoverRightBottomRect.Width * assetScale),
185+
(int)(MaskWindowConfig.UidCoverRightBottomRect.Height * assetScale));
186+
mat2.Rectangle(rect, Scalar.White, -1);
187+
Cv2.ImWrite(savePath, mat2);
188+
}).Start();
185189
}
186-
new Task(() =>
190+
else
187191
{
188-
Cv2.ImWrite(savePath, mat);
189-
}).Start();
192+
new Task(() =>
193+
{
194+
Cv2.ImWrite(savePath, mat);
195+
}).Start();
196+
}
190197
}
191198

192199
public void Reset()

BetterGenshinImpact/GameTask/CaptureContent.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
using BetterGenshinImpact.GameTask.Model.Area;
22
using System;
3-
using System.Drawing;
4-
using Fischless.GameCapture;
53
using OpenCvSharp;
64

75
namespace BetterGenshinImpact.GameTask;
@@ -18,9 +16,9 @@ public class CaptureContent : IDisposable
1816

1917
public int FrameRate => (int)(1000 / TimerInterval);
2018

21-
public ImageRegion CaptureRectArea { get; private set; }
19+
public ImageRegion CaptureRectArea { get; }
2220

23-
public CaptureContent(CaptureImageRes image, int frameIndex, double interval)
21+
public CaptureContent(Mat image, int frameIndex, double interval)
2422
{
2523
FrameIndex = frameIndex;
2624
TimerInterval = interval;
@@ -42,5 +40,11 @@ public CaptureContent(ImageRegion ra)
4240
public void Dispose()
4341
{
4442
CaptureRectArea.Dispose();
43+
GC.SuppressFinalize(this);
4544
}
46-
}
45+
46+
~CaptureContent()
47+
{
48+
Dispose();
49+
}
50+
}

BetterGenshinImpact/GameTask/Common/TaskControl.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ public static async Task Delay(int millisecondsTimeout, CancellationToken ct)
182182
}
183183
}
184184

185-
public static CaptureImageRes CaptureGameImage(IGameCapture? gameCapture)
185+
public static Mat CaptureGameImage(IGameCapture? gameCapture)
186186
{
187187
var image = gameCapture?.Capture();
188188
if (image == null)
@@ -208,7 +208,7 @@ public static CaptureImageRes CaptureGameImage(IGameCapture? gameCapture)
208208
}
209209
}
210210

211-
public static CaptureImageRes? CaptureGameImageNoRetry(IGameCapture? gameCapture)
211+
public static Mat? CaptureGameImageNoRetry(IGameCapture? gameCapture)
212212
{
213213
return gameCapture?.Capture();
214214
}

BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public static void DesktopRegionMoveBy(double dx, double dy)
6969
Simulation.SendInput.Mouse.MoveMouseBy((int)dx, (int)dy);
7070
}
7171

72-
public GameCaptureRegion Derive(CaptureImageRes captureMat, int x, int y)
72+
public GameCaptureRegion Derive(Mat captureMat, int x, int y)
7373
{
7474
return new GameCaptureRegion(captureMat, x, y, this, new TranslationConverter(x, y));
7575
}

BetterGenshinImpact/GameTask/Model/Area/GameCaptureRegion.cs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,8 @@ namespace BetterGenshinImpact.GameTask.Model.Area;
1212
/// 游戏捕获区域类
1313
/// 主要用于转换到遮罩窗口的坐标
1414
/// </summary>
15-
public class GameCaptureRegion : ImageRegion
15+
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)
1616
{
17-
public GameCaptureRegion(Mat mat, int initX, int initY, Region? owner = null, INodeConverter? converter = null,
18-
DrawContent? drawContent = null) : base(mat, initX, initY, owner, converter, drawContent)
19-
{
20-
}
21-
22-
public GameCaptureRegion(CaptureImageRes image, int initX, int initY, Region? owner = null,
23-
INodeConverter? converter = null, DrawContent? drawContent = null) : base(image, initX, initY, owner, converter, drawContent)
24-
{
25-
}
26-
27-
2817
/// <summary>
2918
/// 在游戏捕获图像的坐标维度进行转换到遮罩窗口的坐标维度
3019
/// </summary>

BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -78,23 +78,6 @@ public ImageRegion(Mat mat, int x, int y, Region? owner = null, INodeConverter?
7878
_srcMat = mat;
7979
}
8080

81-
public ImageRegion(CaptureImageRes image, int x, int y, Region? owner = null, INodeConverter? converter = null,
82-
DrawContent? drawContent = null) : base(x, y, image.Width, image.Height, owner, converter, drawContent)
83-
{
84-
if (image.Bitmap != null)
85-
{
86-
_srcBitmap = image.Bitmap;
87-
}
88-
else if (image.Mat != null)
89-
{
90-
_srcMat = image.Mat;
91-
}
92-
else
93-
{
94-
throw new Exception("ImageRegion的构造函数参数错误");
95-
}
96-
}
97-
9881
private bool HasImage()
9982
{
10083
return _srcBitmap != null || _srcMat != null;

BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,12 @@ public void TakeScreenshot()
386386
Directory.CreateDirectory(path);
387387
}
388388

389-
var image = TaskControl.CaptureGameImage(GameCapture);
390-
var mat = image.ForceGetMat();
391-
if (mat == null)
389+
Mat mat;
390+
try
391+
{
392+
mat = TaskControl.CaptureGameImage(GameCapture);
393+
}
394+
catch (Exception)
392395
{
393396
_logger.LogInformation("截图失败,未获取到图像");
394397
return;
@@ -410,6 +413,8 @@ public void TakeScreenshot()
410413
Cv2.ImWrite(savePath, mat);
411414
}
412415

416+
mat.Dispose();
417+
413418
_logger.LogInformation("截图已保存: {Name}", name);
414419
}
415420
catch (Exception e)

BetterGenshinImpact/Helpers/Extensions/BitmapExtension.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,55 @@
11
using OpenCvSharp;
2+
using System;
23
using System.Drawing;
34
using System.IO;
5+
using System.Windows.Media;
46
using System.Windows.Media.Imaging;
7+
using Color = System.Drawing.Color;
58

69
namespace BetterGenshinImpact.Helpers.Extensions
710
{
811
public static class BitmapExtension
912
{
13+
public static BitmapSource ToBitmapSource(this Bitmap bitmap)
14+
{
15+
return bitmap.ToBitmapSource(out _);
16+
}
17+
18+
public static BitmapSource ToBitmapSource(this Bitmap bitmap, out bool bottomUp)
19+
{
20+
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
21+
System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
22+
23+
var stride = bitmapData.Stride;
24+
var buffer = bitmapData.Scan0;
25+
if (stride < 0)
26+
{
27+
bottomUp = true;
28+
stride = -stride;
29+
buffer -= stride * (bitmapData.Height - 1);
30+
}
31+
else
32+
{
33+
bottomUp = false;
34+
}
35+
36+
var pixelFormat = bitmap.PixelFormat switch
37+
{
38+
System.Drawing.Imaging.PixelFormat.Format24bppRgb => PixelFormats.Bgr24,
39+
System.Drawing.Imaging.PixelFormat.Format32bppArgb => PixelFormats.Bgra32,
40+
_ => throw new NotSupportedException($"Unsupported pixel format {bitmap.PixelFormat}")
41+
};
42+
43+
var bitmapSource = BitmapSource.Create(
44+
bitmapData.Width, bitmapData.Height,
45+
bitmap.HorizontalResolution, bitmap.VerticalResolution,
46+
pixelFormat, null,
47+
buffer, stride * bitmapData.Height, stride);
48+
49+
bitmap.UnlockBits(bitmapData);
50+
51+
return bitmapSource;
52+
}
1053

1154
public static BitmapImage ToBitmapImage(this Bitmap bitmap)
1255
{

BetterGenshinImpact/Helpers/Extensions/EnumExtensions.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,23 @@ public static string GetDescription(this Enum value)
1717
.FirstOrDefault()
1818
?.Description ?? value.ToString();
1919
}
20-
20+
21+
public static int GetOrder(this Enum value)
22+
{
23+
return value.GetType()
24+
.GetField(value.ToString())
25+
?.GetCustomAttributes(typeof(DefaultValueAttribute), false)
26+
.Cast<DefaultValueAttribute>()
27+
.FirstOrDefault()
28+
?.Value as int? ?? 0;
29+
}
30+
2131
public static IEnumerable<EnumItem<T>> ToEnumItems<T>() where T : Enum
2232
{
2333
return Enum.GetValues(typeof(T))
2434
.Cast<T>()
25-
.Select(EnumItem<T>.Create);
35+
.Select(EnumItem<T>.Create)
36+
.OrderBy(x => x.Order)
37+
.ThenBy(x => x.Value);
2638
}
27-
}
39+
}

BetterGenshinImpact/Model/EnumItem.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public class EnumItem<T> where T : Enum
77
{
88
public T Value { get; set; }
99
public string DisplayName { get; set; }
10+
public int Order { get; set; }
1011
public string EnumName => Value.ToString();
1112

1213
// 提供一个静态工厂方法来创建实例
@@ -15,7 +16,10 @@ public static EnumItem<T> Create(T value)
1516
return new EnumItem<T>
1617
{
1718
Value = value,
18-
DisplayName = value.GetDescription() // 使用扩展方法获取Description
19+
DisplayName = value.GetDescription(), // 使用扩展方法获取Description
20+
Order = value.GetOrder()
1921
};
2022
}
21-
}
23+
24+
25+
}

0 commit comments

Comments
 (0)