mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-15 19:27:56 +01:00
[Text Extractor] Restructuring Screen scale handling (#31646)
* [Text Extractor] Restructuring Screen scale handling * spell checker * Update src/modules/PowerOCR/PowerOCR/Helpers/WPFExtensionMethods.cs Co-authored-by: Jay <65828559+Jay-o-Way@users.noreply.github.com> * Update src/modules/PowerOCR/PowerOCR/Helpers/WPFExtensionMethods.cs * Adding a workaround to move the window in the desired position * Restructure coordinate calculations. --------- Co-authored-by: Jay <65828559+Jay-o-Way@users.noreply.github.com>
This commit is contained in:
@@ -47,51 +47,17 @@ internal sealed class ImageMethods
|
||||
return destination;
|
||||
}
|
||||
|
||||
internal static ImageSource GetWindowBoundsImage(Window passedWindow)
|
||||
internal static ImageSource GetWindowBoundsImage(OCROverlay passedWindow)
|
||||
{
|
||||
DpiScale dpi = VisualTreeHelper.GetDpi(passedWindow);
|
||||
int windowWidth = (int)(passedWindow.ActualWidth * dpi.DpiScaleX);
|
||||
int windowHeight = (int)(passedWindow.ActualHeight * dpi.DpiScaleY);
|
||||
|
||||
System.Windows.Point absPosPoint = passedWindow.GetAbsolutePosition();
|
||||
int thisCorrectedLeft = (int)absPosPoint.X;
|
||||
int thisCorrectedTop = (int)absPosPoint.Y;
|
||||
|
||||
using Bitmap bmp = new(windowWidth, windowHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||
Rectangle screenRectangle = passedWindow.GetScreenRectangle();
|
||||
using Bitmap bmp = new(screenRectangle.Width, screenRectangle.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||
using Graphics g = Graphics.FromImage(bmp);
|
||||
|
||||
g.CopyFromScreen(thisCorrectedLeft, thisCorrectedTop, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
|
||||
g.CopyFromScreen(screenRectangle.Left, screenRectangle.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
|
||||
return BitmapToImageSource(bmp);
|
||||
}
|
||||
|
||||
internal static Bitmap GetWindowBoundsBitmap(Window passedWindow)
|
||||
{
|
||||
DpiScale dpi = VisualTreeHelper.GetDpi(passedWindow);
|
||||
int windowWidth = (int)(passedWindow.ActualWidth * dpi.DpiScaleX);
|
||||
int windowHeight = (int)(passedWindow.ActualHeight * dpi.DpiScaleY);
|
||||
|
||||
System.Windows.Point absPosPoint = passedWindow.GetAbsolutePosition();
|
||||
int thisCorrectedLeft = (int)absPosPoint.X;
|
||||
int thisCorrectedTop = (int)absPosPoint.Y;
|
||||
|
||||
Bitmap bmp = new(
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||
using Graphics g = Graphics.FromImage(bmp);
|
||||
|
||||
g.CopyFromScreen(
|
||||
thisCorrectedLeft,
|
||||
thisCorrectedTop,
|
||||
0,
|
||||
0,
|
||||
bmp.Size,
|
||||
CopyPixelOperation.SourceCopy);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
internal static Bitmap GetRegionAsBitmap(Window passedWindow, Rectangle selectedRegion)
|
||||
internal static Bitmap GetRegionAsBitmap(OCROverlay passedWindow, Rectangle selectedRegion)
|
||||
{
|
||||
Bitmap bmp = new(
|
||||
selectedRegion.Width,
|
||||
@@ -99,15 +65,11 @@ internal sealed class ImageMethods
|
||||
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||
|
||||
using Graphics g = Graphics.FromImage(bmp);
|
||||
|
||||
System.Windows.Point absPosPoint = passedWindow.GetAbsolutePosition();
|
||||
|
||||
int thisCorrectedLeft = (int)absPosPoint.X + selectedRegion.Left;
|
||||
int thisCorrectedTop = (int)absPosPoint.Y + selectedRegion.Top;
|
||||
Rectangle screenRectangle = passedWindow.GetScreenRectangle();
|
||||
|
||||
g.CopyFromScreen(
|
||||
thisCorrectedLeft,
|
||||
thisCorrectedTop,
|
||||
screenRectangle.Left + selectedRegion.Left,
|
||||
screenRectangle.Top + selectedRegion.Top,
|
||||
0,
|
||||
0,
|
||||
bmp.Size,
|
||||
@@ -117,7 +79,7 @@ internal sealed class ImageMethods
|
||||
return bmp;
|
||||
}
|
||||
|
||||
internal static async Task<string> GetRegionsText(Window? passedWindow, Rectangle selectedRegion, Language? preferredLanguage)
|
||||
internal static async Task<string> GetRegionsText(OCROverlay? passedWindow, Rectangle selectedRegion, Language? preferredLanguage)
|
||||
{
|
||||
if (passedWindow is null)
|
||||
{
|
||||
@@ -130,17 +92,15 @@ internal sealed class ImageMethods
|
||||
return resultText != null ? resultText.Trim() : string.Empty;
|
||||
}
|
||||
|
||||
internal static async Task<string> GetClickedWord(Window passedWindow, System.Windows.Point clickedPoint, Language? preferredLanguage)
|
||||
internal static async Task<string> GetClickedWord(OCROverlay passedWindow, System.Windows.Point clickedPoint, Language? preferredLanguage)
|
||||
{
|
||||
DpiScale dpi = VisualTreeHelper.GetDpi(passedWindow);
|
||||
Bitmap bmp = new((int)(passedWindow.ActualWidth * dpi.DpiScaleX), (int)(passedWindow.ActualHeight * dpi.DpiScaleY), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||
Rectangle screenRectangle = passedWindow.GetScreenRectangle();
|
||||
Bitmap bmp = new((int)screenRectangle.Width, (int)passedWindow.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||
Graphics g = Graphics.FromImage(bmp);
|
||||
|
||||
System.Windows.Point absPosPoint = passedWindow.GetAbsolutePosition();
|
||||
int thisCorrectedLeft = (int)absPosPoint.X;
|
||||
int thisCorrectedTop = (int)absPosPoint.Y;
|
||||
|
||||
g.CopyFromScreen(thisCorrectedLeft, thisCorrectedTop, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
|
||||
g.CopyFromScreen((int)absPosPoint.X, (int)absPosPoint.Y, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
|
||||
|
||||
System.Windows.Point adjustedPoint = new(clickedPoint.X, clickedPoint.Y);
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace PowerOCR.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<string> GetRegionsTextAsTableAsync(Window passedWindow, Rectangle regionScaled, Language? language)
|
||||
public static async Task<string> GetRegionsTextAsTableAsync(OCROverlay passedWindow, Rectangle regionScaled, Language? language)
|
||||
{
|
||||
if (language is null)
|
||||
{
|
||||
|
||||
@@ -37,4 +37,28 @@ public static class WPFExtensionMethods
|
||||
|
||||
return new Point(r.X, r.Y);
|
||||
}
|
||||
|
||||
public static DpiScale GetDpi(this System.Windows.Forms.Screen screen)
|
||||
{
|
||||
var point = new System.Drawing.Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1);
|
||||
var mon = MonitorFromPoint(point, 2/*MONITOR_DEFAULTTONEAREST*/);
|
||||
GetDpiForMonitor(mon, DpiType.Effective, out uint dpiX, out uint dpiY);
|
||||
return new DpiScale(dpiX / 96.0, dpiY / 96.0);
|
||||
}
|
||||
|
||||
// https://msdn.microsoft.com/library/windows/desktop/dd145062(v=vs.85).aspx
|
||||
[DllImport("User32.dll")]
|
||||
private static extern IntPtr MonitorFromPoint([In] System.Drawing.Point pt, [In] uint dwFlags);
|
||||
|
||||
// https://msdn.microsoft.com/library/windows/desktop/dn280510(v=vs.85).aspx
|
||||
[DllImport("Shcore.dll")]
|
||||
private static extern IntPtr GetDpiForMonitor([In] IntPtr hmonitor, [In] DpiType dpiType, [Out] out uint dpiX, [Out] out uint dpiY);
|
||||
|
||||
// https://msdn.microsoft.com/library/windows/desktop/dn280511(v=vs.85).aspx
|
||||
public enum DpiType
|
||||
{
|
||||
Effective = 0,
|
||||
Angular = 1,
|
||||
Raw = 2,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,9 @@ public static class WindowUtilities
|
||||
Logger.LogInfo($"Adding Overlays for each screen");
|
||||
foreach (Screen screen in Screen.AllScreens)
|
||||
{
|
||||
Logger.LogInfo($"screen {screen}");
|
||||
OCROverlay overlay = new(screen.Bounds);
|
||||
DpiScale dpiScale = screen.GetDpi();
|
||||
Logger.LogInfo($"screen {screen}, dpiScale {dpiScale.DpiScaleX}, {dpiScale.DpiScaleY}");
|
||||
OCROverlay overlay = new(screen.Bounds, dpiScale);
|
||||
|
||||
overlay.Show();
|
||||
ActivateWindow(overlay);
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
xmlns:p="clr-namespace:PowerOCR.Properties"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
Title="TextExtractor"
|
||||
Width="200"
|
||||
Height="200"
|
||||
ui:Design.Background="Transparent"
|
||||
AllowsTransparency="True"
|
||||
Background="Transparent"
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using Common.UI;
|
||||
using ManagedCommon;
|
||||
@@ -42,11 +44,21 @@ public partial class OCROverlay : Window
|
||||
private bool isComboBoxReady;
|
||||
private const double ActiveOpacity = 0.4;
|
||||
private readonly UserSettings userSettings = new(new ThrottledActionInvoker());
|
||||
private System.Drawing.Rectangle screenRectangle;
|
||||
private DpiScale dpiScale;
|
||||
|
||||
public OCROverlay(System.Drawing.Rectangle screenRectangle)
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint);
|
||||
|
||||
public OCROverlay(System.Drawing.Rectangle screenRectangleParam, DpiScale dpiScaleParam)
|
||||
{
|
||||
Left = screenRectangle.Left >= 0 ? screenRectangle.Left : screenRectangle.Left + (screenRectangle.Width / 2);
|
||||
Top = screenRectangle.Top >= 0 ? screenRectangle.Top : screenRectangle.Top + (screenRectangle.Height / 2);
|
||||
screenRectangle = screenRectangleParam;
|
||||
dpiScale = dpiScaleParam;
|
||||
|
||||
Left = screenRectangle.Left;
|
||||
Top = screenRectangle.Top;
|
||||
Width = screenRectangle.Width / dpiScale.DpiScaleX;
|
||||
Height = screenRectangle.Height / dpiScale.DpiScaleY;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
@@ -106,7 +118,6 @@ public partial class OCROverlay : Window
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowState = WindowState.Maximized;
|
||||
FullWindow.Rect = new Rect(0, 0, Width, Height);
|
||||
KeyDown += MainWindow_KeyDown;
|
||||
KeyUp += MainWindow_KeyUp;
|
||||
@@ -119,6 +130,12 @@ public partial class OCROverlay : Window
|
||||
#if DEBUG
|
||||
Topmost = false;
|
||||
#endif
|
||||
IntPtr hwnd = new WindowInteropHelper(this).Handle;
|
||||
|
||||
// The first move puts it on the correct monitor, which triggers WM_DPICHANGED
|
||||
// The +1/-1 coerces WPF to update Window.Top/Left/Width/Height in the second move
|
||||
MoveWindow(hwnd, (int)(screenRectangle.Left + 1), (int)screenRectangle.Top, (int)(screenRectangle.Width - 1), (int)screenRectangle.Height, false);
|
||||
MoveWindow(hwnd, (int)screenRectangle.Left, (int)screenRectangle.Top, (int)screenRectangle.Width, (int)screenRectangle.Height, true);
|
||||
}
|
||||
|
||||
private void Window_Unloaded(object sender, RoutedEventArgs e)
|
||||
@@ -476,4 +493,9 @@ public partial class OCROverlay : Window
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public System.Drawing.Rectangle GetScreenRectangle()
|
||||
{
|
||||
return screenRectangle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,12 @@
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||
PerMonitor
|
||||
</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user