From 82f53679bcae902bbb21f522cb0ed35b7c409822 Mon Sep 17 00:00:00 2001 From: MakesYT <2696703792@qq.com> Date: Sun, 5 Jan 2025 00:21:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E6=88=AA=E5=9B=BE=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core.Window/ScreenCapture/CaptureTool.cs | 57 ++++++++++------- .../ScreenCapture/ScreenCaptureByDx11.cs | 1 + .../ScreenCapture/ScreenCaptureByWGC.cs | 62 ++++++++++++++++--- .../Windows/ScreenCaptureWindow.axaml.cs | 38 ++++++++---- ...aptureInfoCustomScenarioValueSerializer.cs | 5 +- KitopiaEx/KitopiaEx.cs | 22 ++++++- KitopiaEx/Ocr/OcrResultShowWindow.axaml.cs | 1 + PluginCore | 2 +- 8 files changed, 140 insertions(+), 48 deletions(-) diff --git a/Core.Window/ScreenCapture/CaptureTool.cs b/Core.Window/ScreenCapture/CaptureTool.cs index 68f658d..ce14cc1 100644 --- a/Core.Window/ScreenCapture/CaptureTool.cs +++ b/Core.Window/ScreenCapture/CaptureTool.cs @@ -13,6 +13,15 @@ public static unsafe byte[] GetBytesSpan(MappedSubresource mappedSubresource, Ou int startY = Math.Clamp(screenCaptureInfo.Y, 0, outputDesc.DesktopCoordinates.Size.Y - 1); int endX = Math.Clamp(screenCaptureInfo.X+screenCaptureInfo.Width, 0, outputDesc.DesktopCoordinates.Size.X); int endY = Math.Clamp(screenCaptureInfo.Y+screenCaptureInfo.Height, 0, outputDesc.DesktopCoordinates.Size.Y); + if (screenCaptureInfo.ScreenCaptureType==ScreenCaptureType.窗口) + { + sizeX=(screenCaptureInfo.WindowInfo.Rect.Width + 3) & ~3; + startX = 0; + startY = 0; + endX = (screenCaptureInfo.WindowInfo.Rect.Width + 3) & ~3; + endY = (int)screenCaptureInfo.WindowInfo.Rect.Height; + } + screenCaptureInfo.Height = endY - startY; screenCaptureInfo.Width = endX - startX; screenCaptureInfo.X = startX; @@ -61,39 +70,39 @@ public static unsafe byte[] GetBytesSpan(MappedSubresource mappedSubresource, Ou ); var span = new ReadOnlySpan(mappedSubresource.PData, (int)mappedSubresource.DepthPitch / 2).ToArray(); - // ReadOnlyMemory readOnlyMemory = new ReadOnlyMemory(span); + // ReadOnlyMemory readOnlyMemory = new ReadOnlyMemory(span); Parallel.For(startY, endY, y => - //for (int y = startY; y < endY; y++) - { + //for (int y = startY; y < endY; y++) + { - int yOffset = y * sizeX; - int targetYOffset = (y - startY) * regionWidth; + int yOffset = y * sizeX; + int targetYOffset = (y - startY) * regionWidth; - for (int x = startX; x < endX; x++) - { - int sourceIndex = (yOffset + x) * 4; - int targetIndex = (targetYOffset + (x - startX)) * 4; + for (int x = startX; x < endX; x++) + { + int sourceIndex = (yOffset + x) * 4; + int targetIndex = (targetYOffset + (x - startX)) * 4; - // 读取并归一化 RGBA 值 + // 读取并归一化 RGBA 值 - float r = float.Log(1 + (float)span[sourceIndex]) / 1.749199854809259f; - float g = float.Log(1 + (float)span[sourceIndex+1]) / 1.749199854809259f; - float b = float.Log(1 + (float)span[sourceIndex+2]) / 1.749199854809259f; + float r = float.Log(1 + (float)span[sourceIndex]) / 1.749199854809259f; + float g = float.Log(1 + (float)span[sourceIndex+1]) / 1.749199854809259f; + float b = float.Log(1 + (float)span[sourceIndex+2]) / 1.749199854809259f; - // 应用色彩转换矩阵 - float bt2020R = matrix[0, 0] * r + matrix[0, 1] * g + matrix[0, 2] * b; - float bt2020G = matrix[1, 0] * r + matrix[1, 1] * g + matrix[1, 2] * b; - float bt2020B = matrix[2, 0] * r + matrix[2, 1] * g + matrix[2, 2] * b; + // 应用色彩转换矩阵 + float bt2020R = matrix[0, 0] * r + matrix[0, 1] * g + matrix[0, 2] * b; + float bt2020G = matrix[1, 0] * r + matrix[1, 1] * g + matrix[1, 2] * b; + float bt2020B = matrix[2, 0] * r + matrix[2, 1] * g + matrix[2, 2] * b; - // 转换并填充结果 + // 转换并填充结果 - result[targetIndex ] = (byte)Math.Clamp(bt2020B * 255,0,255); - result[targetIndex + 1] = (byte)Math.Clamp(bt2020G * 255,0,255); - result[targetIndex+ 2] = (byte)Math.Clamp(bt2020R * 255,0,255); - result[targetIndex + 3] = 255; // Alpha 固定为 255 + result[targetIndex ] = (byte)Math.Clamp(bt2020B * 255,0,255); + result[targetIndex + 1] = (byte)Math.Clamp(bt2020G * 255,0,255); + result[targetIndex+ 2] = (byte)Math.Clamp(bt2020R * 255,0,255); + result[targetIndex + 3] = 255; // Alpha 固定为 255 + } } - } - ); + ); } diff --git a/Core.Window/ScreenCapture/ScreenCaptureByDx11.cs b/Core.Window/ScreenCapture/ScreenCaptureByDx11.cs index 1d49df2..0ea9698 100644 --- a/Core.Window/ScreenCapture/ScreenCaptureByDx11.cs +++ b/Core.Window/ScreenCapture/ScreenCaptureByDx11.cs @@ -32,6 +32,7 @@ using SixLabors.ImageSharp.PixelFormats; using Vanara.Extensions.Reflection; using Vanara.PInvoke; +using Rect = PluginCore.Rect; namespace Core.Window; diff --git a/Core.Window/ScreenCapture/ScreenCaptureByWGC.cs b/Core.Window/ScreenCapture/ScreenCaptureByWGC.cs index ed08b56..56d3102 100644 --- a/Core.Window/ScreenCapture/ScreenCaptureByWGC.cs +++ b/Core.Window/ScreenCapture/ScreenCaptureByWGC.cs @@ -17,6 +17,7 @@ using IDirect3DDevice = Windows.Graphics.DirectX.Direct3D11.IDirect3DDevice; using IDirect3DSurface = Windows.Graphics.DirectX.Direct3D11.IDirect3DSurface; using IInspectable = WinRT.IInspectable; +using Rect = PluginCore.Rect; namespace Core.Window; @@ -74,12 +75,12 @@ public List GetAllWindowInfo() zIndex++; currentHwnd = User32.GetWindow(currentHwnd, User32.GetWindowCmd.GW_HWNDNEXT); // 忽略有父窗口的和不可见的窗口 - if (!User32.GetParent(currentHwnd).IsNull || !User32.IsWindowVisible(currentHwnd)|| User32.IsIconic(currentHwnd)) + if (!User32.GetParent(currentHwnd).IsNull || !User32.IsWindowVisible(currentHwnd)) { continue; } int style = User32.GetWindowLong(currentHwnd,User32.WindowLongFlags.GWL_STYLE); - if ((style & WS_POPUP) != 0 || (style & WS_CHILD) != 0) + if ( (style & WS_CHILD) != 0) { continue; } @@ -264,17 +265,61 @@ public static (ComPtr,OutputDesc1) GetAdapterForMonitor(ComPtr(); - var itemPointer = interop.CreateForMonitor(screenCaptureInfo.ScreenInfo.hMonitor, GraphicsCaptureItemGuid); + IntPtr itemPointer = IntPtr.Zero; + switch (screenCaptureInfo.ScreenCaptureType) + { + case ScreenCaptureType.屏幕: + { + itemPointer= interop.CreateForMonitor(screenCaptureInfo.ScreenInfo.hMonitor, GraphicsCaptureItemGuid); + break; + } + case ScreenCaptureType.窗口: + { + + itemPointer= interop.CreateForWindow(screenCaptureInfo.WindowInfo.Hwnd, GraphicsCaptureItemGuid); + break; + } + + } var item = MarshalInterface.FromAbi(itemPointer); var dxgi = new DXGI(new DefaultNativeContext("dxgi")); @@ -375,6 +420,9 @@ IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(ID3D11Device* d3dDevice) immediateContext->CopyResource(stagingResource, bitmap); if (immediateContext->Map(stagingResource, 0, Map.Read, 0, &mappedSubresource) != 0) throw new Exception("Failed to map staging texture"); + + //更新窗口的Size数据 + screenCaptureInfo.WindowInfo.Rect = new Rect(0,0,item.Size.Width, item.Size.Height); var bytesSpan = CaptureTool.GetBytesSpan(mappedSubresource,adapterForMonitor.Item2,ref screenCaptureInfo); return new ScreenCaptureResult() diff --git a/KitopiaAvalonia/Windows/ScreenCaptureWindow.axaml.cs b/KitopiaAvalonia/Windows/ScreenCaptureWindow.axaml.cs index 299f280..79e5cbc 100644 --- a/KitopiaAvalonia/Windows/ScreenCaptureWindow.axaml.cs +++ b/KitopiaAvalonia/Windows/ScreenCaptureWindow.axaml.cs @@ -26,6 +26,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using Point = Avalonia.Point; +using Rect = PluginCore.Rect; using Rectangle = SixLabors.ImageSharp.Rectangle; using Size = Avalonia.Size; @@ -47,6 +48,7 @@ public partial class ScreenCaptureWindow : Window private ScreenCaptureInfo _screenCaptureInfo; private bool Finish = false; private List _windowInfos; + private WindowInfo _currentWindowInfo; public ScreenCaptureWindow(ScreenCaptureInfo screenCaptureInfo) { InitializeComponent(); @@ -292,7 +294,7 @@ protected override void OnPointerMoved(PointerEventArgs e) SelectBox.Width = selectBoxWidth; SelectBox._dragTransform.X = _startPoint.X; } - + _currentWindowInfo=new WindowInfo(); UpdateSelectBox(); } @@ -317,7 +319,9 @@ protected override void OnPointerMoved(PointerEventArgs e) } else { + var windowInfo = firstOrDefault.FirstOrDefault(); + _currentWindowInfo=windowInfo; _startPoint=new Point(windowInfo.Rect.X*screenInfoWidth,windowInfo.Rect.Y*screenInfoHeight); SelectBox._dragTransform.X = _startPoint.X; SelectBox._dragTransform.Y = _startPoint.Y; @@ -553,7 +557,7 @@ private void SelectBox_OnPointerMoved(object? sender, PointerEventArgs e) ellipse.Width = round; ellipse.Height = round; ellipse.Measure(new Size(round, round)); - ellipse.Arrange(new Rect(new Point(0, 0), new Size(round, round))); + ellipse.Arrange(new Avalonia.Rect(new Point(0, 0), new Size(round, round))); renderTargetBitmap.Render(ellipse); SelectBox.Cursor.Dispose(); SelectBox.Cursor = new Cursor(renderTargetBitmap, @@ -575,7 +579,7 @@ private void SelectBox_OnPointerMoved(object? sender, PointerEventArgs e) ellipse.Width = round; ellipse.Height = round; ellipse.Measure(new Size(round, round)); - ellipse.Arrange(new Rect(new Point(0, 0), new Size(round, round))); + ellipse.Arrange(new Avalonia.Rect(new Point(0, 0), new Size(round, round))); renderTargetBitmap.Render(ellipse); SelectBox.Cursor.Dispose(); SelectBox.Cursor = new Cursor(renderTargetBitmap, @@ -758,11 +762,11 @@ private void UpdateSelectBox() { var fullScreenRect = new RectangleGeometry { - Rect = new Rect(0, 0, Bounds.Width, Bounds.Height) + Rect = new Avalonia.Rect(0, 0, Bounds.Width, Bounds.Height) }; var selectionRect = new RectangleGeometry { - Rect = new Rect(new Point(SelectBox._dragTransform.X, SelectBox._dragTransform.Y), SelectBox.DesiredSize) + Rect = new Avalonia.Rect(new Point(SelectBox._dragTransform.X, SelectBox._dragTransform.Y), SelectBox.DesiredSize) }; @@ -830,15 +834,23 @@ private void FinnishCapture() else cropH = (int)selectBoxHeight + (int)dragTransformY; if (selectMode) { - selectModeAction.Invoke(new ScreenCaptureInfo() + if (_currentWindowInfo.Hwnd != IntPtr.Zero) + selectModeAction.Invoke(new ScreenCaptureInfo() + { + ScreenCaptureType = ScreenCaptureType.窗口, + WindowInfo = _currentWindowInfo, + }); + else { - - X = Math.Max((int)dragTransformX, 0), - Y = Math.Max((int)dragTransformY, 0), - Width = cropW, - Height = cropH, - ScreenInfo = _screenCaptureInfo.ScreenInfo - }); + selectModeAction.Invoke(new ScreenCaptureInfo() + { + X = Math.Max((int)dragTransformX, 0), + Y = Math.Max((int)dragTransformY, 0), + Width = cropW, + Height = cropH, + ScreenInfo = _screenCaptureInfo.ScreenInfo + }); + } } else{ foreach (var canvasChild in Canvas.Children) if (canvasChild is CaptureToolBase draggableResizeableControl) diff --git a/KitopiaEx/CustomScenarioValueSerializer/ScreenCaptureInfoCustomScenarioValueSerializer.cs b/KitopiaEx/CustomScenarioValueSerializer/ScreenCaptureInfoCustomScenarioValueSerializer.cs index 4bef669..cc1b17b 100644 --- a/KitopiaEx/CustomScenarioValueSerializer/ScreenCaptureInfoCustomScenarioValueSerializer.cs +++ b/KitopiaEx/CustomScenarioValueSerializer/ScreenCaptureInfoCustomScenarioValueSerializer.cs @@ -14,7 +14,7 @@ public string Serialize(T value) { return ""; } - return $"WindowInfo.Title={screenCaptureInfo.WindowInfo.Title},ScreenInfo.X={screenCaptureInfo.ScreenInfo.X},ScreenInfo.Y={screenCaptureInfo.ScreenInfo.Y},ScreenInfo.Height={screenCaptureInfo.ScreenInfo.Height},ScreenInfo.Width={screenCaptureInfo.ScreenInfo.Width},{nameof(screenCaptureInfo.X)}={screenCaptureInfo.X},{nameof(screenCaptureInfo.Y)}={screenCaptureInfo.Y},{nameof(screenCaptureInfo.Width)}={screenCaptureInfo.Width},{nameof(screenCaptureInfo.Height)}={screenCaptureInfo.Height}"; + return $"ScreenCaptureType={screenCaptureInfo.ScreenCaptureType},WindowInfo.Title={screenCaptureInfo.WindowInfo.Title},ScreenInfo.X={screenCaptureInfo.ScreenInfo.X},ScreenInfo.Y={screenCaptureInfo.ScreenInfo.Y},ScreenInfo.Height={screenCaptureInfo.ScreenInfo.Height},ScreenInfo.Width={screenCaptureInfo.ScreenInfo.Width},{nameof(screenCaptureInfo.X)}={screenCaptureInfo.X},{nameof(screenCaptureInfo.Y)}={screenCaptureInfo.Y},{nameof(screenCaptureInfo.Width)}={screenCaptureInfo.Width},{nameof(screenCaptureInfo.Height)}={screenCaptureInfo.Height}"; } public object Deserialize(ReadOnlySpan value) @@ -22,7 +22,7 @@ public object Deserialize(ReadOnlySpan value) var str = Encoding.UTF8.GetString(value); var split = str.Split(','); - if (split.Length != 9) + if (split.Length != 10) { return null; } @@ -36,6 +36,7 @@ public object Deserialize(ReadOnlySpan value) var screenCaptureInfo = new ScreenCaptureInfo { + ScreenCaptureType = Enum.Parse(dic["ScreenCaptureType"]), ScreenInfo = new ScreenInfo { Height = int.Parse(dic["ScreenInfo.Height"]), diff --git a/KitopiaEx/KitopiaEx.cs b/KitopiaEx/KitopiaEx.cs index dedbfab..4abb284 100644 --- a/KitopiaEx/KitopiaEx.cs +++ b/KitopiaEx/KitopiaEx.cs @@ -25,6 +25,16 @@ public void OnEnabled(IServiceProvider serviceProvider) Kitopia.ToolTipConverters.TryAdd(typeof(ScreenCaptureInfo), info => { var screenCaptureInfo = (ScreenCaptureInfo)info; + if (screenCaptureInfo.ScreenCaptureType == ScreenCaptureType.屏幕) + { + return + $"显示器:{screenCaptureInfo.ScreenInfo.hMonitor},起始坐标:{screenCaptureInfo.X},{screenCaptureInfo.Y}\n大小:{screenCaptureInfo.Width}x{screenCaptureInfo.Height}"; + } + if (screenCaptureInfo.ScreenCaptureType == ScreenCaptureType.窗口) + { + return + $"窗口:{screenCaptureInfo.WindowInfo.Title}"; + } return $"显示器:{screenCaptureInfo.ScreenInfo.hMonitor},起始坐标:{screenCaptureInfo.X},{screenCaptureInfo.Y}\n大小:{screenCaptureInfo.Width}x{screenCaptureInfo.Height}"; }); @@ -32,8 +42,18 @@ public void OnEnabled(IServiceProvider serviceProvider) { var screenCaptureResult = (ScreenCaptureResult)e; var screenCaptureInfo = screenCaptureResult.Info; + if (screenCaptureInfo.ScreenCaptureType == ScreenCaptureType.屏幕) + { + return + $"显示器:{screenCaptureInfo.ScreenInfo.hMonitor},起始坐标:{screenCaptureInfo.X},{screenCaptureInfo.Y}\n大小:{screenCaptureInfo.Width}x{screenCaptureInfo.Height}"; + } + if (screenCaptureInfo.ScreenCaptureType == ScreenCaptureType.窗口) + { + return + $"窗口:{screenCaptureInfo.WindowInfo.Title}"; + } return - $"显示器:{screenCaptureInfo.ScreenInfo.hMonitor},起始坐标:{screenCaptureInfo.X},{screenCaptureInfo.Y}\n大小:{screenCaptureInfo.Width}x{screenCaptureInfo.Height}\nByte数据:{(screenCaptureResult.Bytes is null?"不存在":"存在")}\nBitmap数据:{(screenCaptureResult.Source is null?"不存在":"存在")}"; + $"起始坐标:{screenCaptureInfo.X},{screenCaptureInfo.Y}\n大小:{screenCaptureInfo.Width}x{screenCaptureInfo.Height}\nByte数据:{(screenCaptureResult.Bytes is null?"不存在":"存在")}\nBitmap数据:{(screenCaptureResult.Source is null?"不存在":"存在")}"; }); Kitopia.JsonConverters.TryAdd(typeof(ScreenCaptureInfo), new ScreenCaptureInfoCustomScenarioValueSerializer()); } diff --git a/KitopiaEx/Ocr/OcrResultShowWindow.axaml.cs b/KitopiaEx/Ocr/OcrResultShowWindow.axaml.cs index 325d7a7..8b2b891 100644 --- a/KitopiaEx/Ocr/OcrResultShowWindow.axaml.cs +++ b/KitopiaEx/Ocr/OcrResultShowWindow.axaml.cs @@ -14,6 +14,7 @@ using Avalonia.Threading; using Microsoft.Extensions.DependencyInjection; using PluginCore; +using Rect = Avalonia.Rect; namespace KitopiaEx.Ocr; diff --git a/PluginCore b/PluginCore index 31072cb..c1cb6c0 160000 --- a/PluginCore +++ b/PluginCore @@ -1 +1 @@ -Subproject commit 31072cb33d5d706a23aaed9242d6fcdb5752c1a9 +Subproject commit c1cb6c0e25dd9fc7fe525d178018f40eb1c1ce9b