ZoomIt smooth image zooming (#42200)

Added smooth image option that results in GDI+ image smoothing for
static zoom and Magnifier API image smoothing for live zoom.

---------

Co-authored-by: Mark Russinovich <markruss@ntdev.microsoft.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
This commit is contained in:
Mark Russinovich
2025-10-07 11:20:00 -07:00
committed by GitHub
parent 14ff4dbc8c
commit e04e6a11d1
10 changed files with 159 additions and 73 deletions

View File

@@ -856,6 +856,7 @@ linkid
LINKOVERLAY LINKOVERLAY
LINQTo LINQTo
listview listview
LIVEDRAW
LIVEZOOM LIVEZOOM
LLKH LLKH
llkhf llkhf
@@ -1237,6 +1238,7 @@ PATPAINT
pbc pbc
pbi pbi
PBlob PBlob
pbrush
pcb pcb
pcch pcch
pcelt pcelt

View File

@@ -96,7 +96,10 @@ typedef struct {
#define SHALLOW_DESTROY 2 #define SHALLOW_DESTROY 2
#define LIVE_DRAW_ZOOM 3 #define LIVE_DRAW_ZOOM 3
#define PEN_COLOR_HIGHLIGHT(Pencolor) (Pencolor >> 24) != 0xFF #define PEN_COLOR_HIGHLIGHT(Pencolor) ((Pencolor >> 24) != 0xFF)
#define PEN_COLOR_BLUR(Pencolor) ((Pencolor & 0x00FFFFFF) == COLOR_BLUR)
#define CURSOR_SAVE_MARGIN 4
typedef BOOL (__stdcall *type_pGetMonitorInfo)( typedef BOOL (__stdcall *type_pGetMonitorInfo)(
@@ -143,6 +146,13 @@ typedef BOOL(__stdcall *type_pMagSetWindowFilterList)(
int count, int count,
HWND* pHWND HWND* pHWND
); );
typedef BOOL(__stdcall* type_pMagSetLensUseBitmapSmoothing)(
_In_ HWND,
_In_ BOOL
);
typedef BOOL(__stdcall* type_MagSetFullscreenUseBitmapSmoothing)(
BOOL fUseBitmapSmoothing
);
typedef BOOL(__stdcall* type_pMagInitialize)(VOID); typedef BOOL(__stdcall* type_pMagInitialize)(VOID);
typedef BOOL(__stdcall *type_pGetPointerType)( typedef BOOL(__stdcall *type_pGetPointerType)(

View File

@@ -2,13 +2,6 @@
// //
#include "resource.h" #include "resource.h"
// version.h and branding.h are different in the Sysinternals repository,
// keep the includes as such, here.
// From $(MSBuildThisFileDirectory)..\..\..\common\version
#include "version.h"
// From $(MSBuildThisFileDirectory)PowerToys
#include "branding.h"
#define APSTUDIO_READONLY_SYMBOLS #define APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
@@ -75,8 +68,8 @@ APPICON ICON "appicon.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION FILE_VERSION FILEVERSION 9,10,0,0
PRODUCTVERSION PRODUCT_VERSION PRODUCTVERSION 9,10,0,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@@ -91,14 +84,14 @@ BEGIN
BEGIN BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", COMPANY_NAME VALUE "CompanyName", "Microsoft Corporation"
VALUE "FileDescription", FILE_DESCRIPTION VALUE "FileDescription", "Sysinternals Screen Magnifier"
VALUE "FileVersion", FILE_VERSION_STRING VALUE "FileVersion", "9.10"
VALUE "InternalName", INTERNAL_NAME VALUE "InternalName", "ZoomIt"
VALUE "LegalCopyright", COPYRIGHT_NOTE VALUE "LegalCopyright", "Copyright (C) Microsoft Corporation. All rights reserved."
VALUE "OriginalFilename", ORIGINAL_FILENAME VALUE "OriginalFilename", "PowerToys.ZoomIt.exe"
VALUE "ProductName", ZOOMIT_PRODUCT_NAME VALUE "ProductName", "PowerToys Sysinternals ZoomIt"
VALUE "ProductVersion", PRODUCT_VERSION_STRING VALUE "ProductVersion", "9.10"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
@@ -122,7 +115,7 @@ BEGIN
DEFPUSHBUTTON "OK",IDOK,166,306,50,14 DEFPUSHBUTTON "OK",IDOK,166,306,50,14
PUSHBUTTON "Cancel",IDCANCEL,223,306,50,14 PUSHBUTTON "Cancel",IDCANCEL,223,306,50,14
LTEXT "ZoomIt v9.01",IDC_VERSION,42,7,73,10 LTEXT "ZoomIt v9.01",IDC_VERSION,42,7,73,10
LTEXT "Copyright © 2006-2025 Mark Russinovich",IDC_COPYRIGHT,42,17,166,8 LTEXT "Copyright <EFBFBD> 2006-2025 Mark Russinovich",IDC_COPYRIGHT,42,17,231,8
CONTROL "<a HREF=""https://www.sysinternals.com"">Sysinternals - www.sysinternals.com</a>",IDC_LINK, CONTROL "<a HREF=""https://www.sysinternals.com"">Sysinternals - www.sysinternals.com</a>",IDC_LINK,
"SysLink",WS_TABSTOP,42,26,150,9 "SysLink",WS_TABSTOP,42,26,150,9
ICON "APPICON",IDC_STATIC,12,9,20,20 ICON "APPICON",IDC_STATIC,12,9,20,20
@@ -149,7 +142,8 @@ BEGIN
CONTROL "",IDC_TIMER_POS7,"Button",BS_AUTORADIOBUTTON,63,108,10,10 CONTROL "",IDC_TIMER_POS7,"Button",BS_AUTORADIOBUTTON,63,108,10,10
CONTROL "",IDC_TIMER_POS8,"Button",BS_AUTORADIOBUTTON,79,108,10,10 CONTROL "",IDC_TIMER_POS8,"Button",BS_AUTORADIOBUTTON,79,108,10,10
CONTROL "",IDC_TIMER_POS9,"Button",BS_AUTORADIOBUTTON,97,108,10,10 CONTROL "",IDC_TIMER_POS9,"Button",BS_AUTORADIOBUTTON,97,108,10,10
CONTROL "Show background bitmap:",IDC_CHECK_BACKGROUND_FILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,122,99,10,WS_EX_RIGHT CONTROL "Show background bitmap:",IDC_CHECK_BACKGROUND_FILE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,122,99,10,WS_EX_RIGHT
CONTROL "Use faded desktop as background",IDC_STATIC_DESKTOP_BACKGROUND, CONTROL "Use faded desktop as background",IDC_STATIC_DESKTOP_BACKGROUND,
"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,46,135,125,10 "Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,46,135,125,10
CONTROL "Use image file as background",IDC_STATIC_BACKGROUND_FILE, CONTROL "Use image file as background",IDC_STATIC_BACKGROUND_FILE,
@@ -165,23 +159,25 @@ BEGIN
CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | SS_SUNKEN,7,196,193,1,WS_EX_CLIENTEDGE CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | SS_SUNKEN,7,196,193,1,WS_EX_CLIENTEDGE
END END
ZOOM DIALOGEX 0, 0, 260, 158 ZOOM DIALOGEX 0, 0, 260, 170
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_SYSMENU STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
CONTROL "",IDC_HOTKEY,"msctls_hotkey32",WS_BORDER | WS_TABSTOP,59,57,80,12 CONTROL "",IDC_HOTKEY,"msctls_hotkey32",WS_BORDER | WS_TABSTOP,59,57,80,12
LTEXT "After toggling ZoomIt you can zoom in with the mouse wheel or up and down arrow keys. Exit zoom mode with Escape or by pressing the right mouse button.",IDC_STATIC,7,6,246,26 LTEXT "After toggling ZoomIt you can zoom in with the mouse wheel or up and down arrow keys. Exit zoom mode with Escape or by pressing the right mouse button.",IDC_STATIC,7,6,246,26
LTEXT "Zoom Toggle:",IDC_STATIC,7,59,51,8 LTEXT "Zoom Toggle:",IDC_STATIC,7,59,51,8
CONTROL "",IDC_ZOOM_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,53,104,150,15,WS_EX_TRANSPARENT CONTROL "",IDC_ZOOM_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,53,118,150,15,WS_EX_TRANSPARENT
LTEXT "Specify the initial level of magnification when zooming in:",IDC_STATIC,7,91,215,10 LTEXT "Specify the initial level of magnification when zooming in:",IDC_STATIC,7,105,215,10
LTEXT "1.25",IDC_STATIC,52,122,16,8 LTEXT "1.25",IDC_STATIC,52,136,16,8
LTEXT "1.5",IDC_STATIC,82,122,12,8 LTEXT "1.5",IDC_STATIC,82,136,12,8
LTEXT "1.75",IDC_STATIC,108,122,16,8 LTEXT "1.75",IDC_STATIC,108,136,16,8
LTEXT "2.0",IDC_STATIC,138,122,12,8 LTEXT "2.0",IDC_STATIC,138,136,12,8
LTEXT "3.0",IDC_STATIC,164,122,12,8 LTEXT "3.0",IDC_STATIC,164,136,12,8
LTEXT "4.0",IDC_STATIC,190,122,12,8 LTEXT "4.0",IDC_STATIC,190,136,12,8
CONTROL "Animate zoom in and zoom out:",IDC_ANIMATE_ZOOM,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,7,74,116,10 CONTROL "Animate zoom in and zoom out:",IDC_ANIMATE_ZOOM,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,7,74,116,10
LTEXT "Copy a zoomed screen with Ctrl+C or save it by typing Ctrl+S. Crop the copy or save region by entering Ctrl+Shift instead of Ctrl.",IDC_STATIC,7,34,246,17 CONTROL "Smooth zoomed image:",IDC_SMOOTH_IMAGE,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,7,88,116,10
LTEXT "Copy a zoomed screen with Ctrl+C or save it by typing Ctrl+S. Crop the copy or save region by entering Ctrl+Shift instead of Ctrl.",IDC_STATIC,7,148,246,17
LTEXT "Copy a zoomed screen with Ctrl+C or save it by typing Ctrl+S. Crop the copy or save region by entering Ctrl+Shift instead of Ctrl.",IDC_STATIC,6,34,246,18
END END
DRAW DIALOGEX 0, 0, 260, 228 DRAW DIALOGEX 0, 0, 260, 228
@@ -295,7 +291,8 @@ BEGIN
LTEXT "DemoType toggle:",IDC_STATIC,7,157,63,8 LTEXT "DemoType toggle:",IDC_STATIC,7,157,63,8
PUSHBUTTON "&...",IDC_DEMOTYPE_BROWSE,231,137,16,13 PUSHBUTTON "&...",IDC_DEMOTYPE_BROWSE,231,137,16,13
CONTROL "",IDC_DEMOTYPE_SPEED_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,52,202,150,11,WS_EX_TRANSPARENT CONTROL "",IDC_DEMOTYPE_SPEED_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,52,202,150,11,WS_EX_TRANSPARENT
CONTROL "Drive input with typing:",IDC_DEMOTYPE_USER_DRIVEN,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,7,173,88,10 CONTROL "Drive input with typing:",IDC_DEMOTYPE_USER_DRIVEN,
"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,7,173,88,10
LTEXT "DemoType typing speed:",IDC_STATIC,7,189,215,10 LTEXT "DemoType typing speed:",IDC_STATIC,7,189,215,10
LTEXT "Slow",IDC_DEMOTYPE_STATIC1,51,213,18,8 LTEXT "Slow",IDC_DEMOTYPE_STATIC1,51,213,18,8
LTEXT "Fast",IDC_DEMOTYPE_STATIC2,186,213,17,8 LTEXT "Fast",IDC_DEMOTYPE_STATIC2,186,213,17,8

View File

@@ -14,6 +14,7 @@ DWORD g_SnipToggleKey = ((HOTKEYF_CONTROL) << 8) | '6';
DWORD g_ShowExpiredTime = 1; DWORD g_ShowExpiredTime = 1;
DWORD g_SliderZoomLevel = 3; DWORD g_SliderZoomLevel = 3;
BOOLEAN g_AnimateZoom = TRUE; BOOLEAN g_AnimateZoom = TRUE;
BOOLEAN g_SmoothImage = TRUE;
DWORD g_PenColor = COLOR_RED; DWORD g_PenColor = COLOR_RED;
DWORD g_BreakPenColor = COLOR_RED; DWORD g_BreakPenColor = COLOR_RED;
DWORD g_RootPenWidth = PEN_WIDTH; DWORD g_RootPenWidth = PEN_WIDTH;
@@ -72,6 +73,7 @@ REG_SETTING RegSettings[] = {
{ L"ShowTrayIcon", SETTING_TYPE_BOOLEAN, 0, &g_ShowTrayIcon, static_cast<DOUBLE>(g_ShowTrayIcon) }, { L"ShowTrayIcon", SETTING_TYPE_BOOLEAN, 0, &g_ShowTrayIcon, static_cast<DOUBLE>(g_ShowTrayIcon) },
// NOTE: AnimateZoom is misspelled, but since it is a user setting stored in the registry we must continue to misspell it. // NOTE: AnimateZoom is misspelled, but since it is a user setting stored in the registry we must continue to misspell it.
{ L"AnimnateZoom", SETTING_TYPE_BOOLEAN, 0, &g_AnimateZoom, static_cast<DOUBLE>(g_AnimateZoom) }, { L"AnimnateZoom", SETTING_TYPE_BOOLEAN, 0, &g_AnimateZoom, static_cast<DOUBLE>(g_AnimateZoom) },
{ L"SmoothImage", SETTING_TYPE_BOOLEAN, 0, &g_SmoothImage, static_cast<DOUBLE>(g_SmoothImage) },
{ L"TelescopeZoomOut", SETTING_TYPE_BOOLEAN, 0, &g_TelescopeZoomOut, static_cast<DOUBLE>(g_TelescopeZoomOut) }, { L"TelescopeZoomOut", SETTING_TYPE_BOOLEAN, 0, &g_TelescopeZoomOut, static_cast<DOUBLE>(g_TelescopeZoomOut) },
{ L"SnapToGrid", SETTING_TYPE_BOOLEAN, 0, &g_SnapToGrid, static_cast<DOUBLE>(g_SnapToGrid) }, { L"SnapToGrid", SETTING_TYPE_BOOLEAN, 0, &g_SnapToGrid, static_cast<DOUBLE>(g_SnapToGrid) },
{ L"ZoominSliderLevel", SETTING_TYPE_DWORD, 0, &g_SliderZoomLevel, static_cast<DOUBLE>(g_SliderZoomLevel) }, { L"ZoominSliderLevel", SETTING_TYPE_DWORD, 0, &g_SliderZoomLevel, static_cast<DOUBLE>(g_SliderZoomLevel) },

View File

@@ -170,6 +170,8 @@ type_pMagSetFullscreenTransform pMagSetFullscreenTransform;
type_pMagSetInputTransform pMagSetInputTransform; type_pMagSetInputTransform pMagSetInputTransform;
type_pMagShowSystemCursor pMagShowSystemCursor; type_pMagShowSystemCursor pMagShowSystemCursor;
type_pMagSetWindowFilterList pMagSetWindowFilterList; type_pMagSetWindowFilterList pMagSetWindowFilterList;
type_MagSetFullscreenUseBitmapSmoothing pMagSetFullscreenUseBitmapSmoothing;
type_pMagSetLensUseBitmapSmoothing pMagSetLensUseBitmapSmoothing;
type_pMagInitialize pMagInitialize; type_pMagInitialize pMagInitialize;
type_pDwmIsCompositionEnabled pDwmIsCompositionEnabled; type_pDwmIsCompositionEnabled pDwmIsCompositionEnabled;
type_pGetPointerType pGetPointerType; type_pGetPointerType pGetPointerType;
@@ -1099,6 +1101,8 @@ void DrawHighlightedShape( DWORD Shape, HDC hdcScreenCompat, Gdiplus::Brush *pBr
// Create a new bitmap that's the size of the area covered by the line + 2 * g_PenWidth // Create a new bitmap that's the size of the area covered by the line + 2 * g_PenWidth
Gdiplus::Rect lineBounds(min(x1, x2), min(y1, y2), abs(x2 - x1), abs(y2 - y1)); Gdiplus::Rect lineBounds(min(x1, x2), min(y1, y2), abs(x2 - x1), abs(y2 - y1));
OutputDebug(L"DrawHighlightedShape\n");
// Expand for line drawing // Expand for line drawing
if (Shape == DRAW_LINE) if (Shape == DRAW_LINE)
lineBounds.Inflate(static_cast<int>(g_PenWidth / 2), static_cast<int>(g_PenWidth / 2)); lineBounds.Inflate(static_cast<int>(g_PenWidth / 2), static_cast<int>(g_PenWidth / 2));
@@ -1284,7 +1288,12 @@ void ScaleImage( HDC hdcDst, float xDst, float yDst, float wDst, float hDst,
{ {
Gdiplus::Bitmap srcBitmap( bmSrc, NULL ); Gdiplus::Bitmap srcBitmap( bmSrc, NULL );
// Use high quality interpolation when smooth image is enabled
if (g_SmoothImage) {
dstGraphics.SetInterpolationMode( Gdiplus::InterpolationModeHighQuality );
} else {
dstGraphics.SetInterpolationMode( Gdiplus::InterpolationModeLowQuality ); dstGraphics.SetInterpolationMode( Gdiplus::InterpolationModeLowQuality );
}
dstGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeHalf ); dstGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeHalf );
dstGraphics.DrawImage( &srcBitmap, Gdiplus::RectF(xDst,yDst,wDst,hDst), xSrc, ySrc, wSrc, hSrc, Gdiplus::UnitPixel ); dstGraphics.DrawImage( &srcBitmap, Gdiplus::RectF(xDst,yDst,wDst,hDst), xSrc, ySrc, wSrc, hSrc, Gdiplus::UnitPixel );
@@ -2071,6 +2080,8 @@ INT_PTR CALLBACK OptionsProc( HWND hDlg, UINT message,
IsAutostartConfigured() ? BST_CHECKED: BST_UNCHECKED ); IsAutostartConfigured() ? BST_CHECKED: BST_UNCHECKED );
CheckDlgButton( g_OptionsTabs[ZOOM_PAGE].hPage, IDC_ANIMATE_ZOOM, CheckDlgButton( g_OptionsTabs[ZOOM_PAGE].hPage, IDC_ANIMATE_ZOOM,
g_AnimateZoom ? BST_CHECKED: BST_UNCHECKED ); g_AnimateZoom ? BST_CHECKED: BST_UNCHECKED );
CheckDlgButton( g_OptionsTabs[ZOOM_PAGE].hPage, IDC_SMOOTH_IMAGE,
g_SmoothImage ? BST_CHECKED: BST_UNCHECKED );
SendMessage( GetDlgItem(g_OptionsTabs[ZOOM_PAGE].hPage, IDC_ZOOM_SLIDER), TBM_SETRANGE, false, MAKELONG(0,_countof(g_ZoomLevels)-1) ); SendMessage( GetDlgItem(g_OptionsTabs[ZOOM_PAGE].hPage, IDC_ZOOM_SLIDER), TBM_SETRANGE, false, MAKELONG(0,_countof(g_ZoomLevels)-1) );
SendMessage( GetDlgItem(g_OptionsTabs[ZOOM_PAGE].hPage, IDC_ZOOM_SLIDER), TBM_SETPOS, true, g_SliderZoomLevel ); SendMessage( GetDlgItem(g_OptionsTabs[ZOOM_PAGE].hPage, IDC_ZOOM_SLIDER), TBM_SETPOS, true, g_SliderZoomLevel );
@@ -2210,6 +2221,7 @@ INT_PTR CALLBACK OptionsProc( HWND hDlg, UINT message,
} }
g_ShowTrayIcon = IsDlgButtonChecked( hDlg, IDC_SHOW_TRAY_ICON ) == BST_CHECKED; g_ShowTrayIcon = IsDlgButtonChecked( hDlg, IDC_SHOW_TRAY_ICON ) == BST_CHECKED;
g_AnimateZoom = IsDlgButtonChecked( g_OptionsTabs[ZOOM_PAGE].hPage, IDC_ANIMATE_ZOOM ) == BST_CHECKED; g_AnimateZoom = IsDlgButtonChecked( g_OptionsTabs[ZOOM_PAGE].hPage, IDC_ANIMATE_ZOOM ) == BST_CHECKED;
g_SmoothImage = IsDlgButtonChecked( g_OptionsTabs[ZOOM_PAGE].hPage, IDC_SMOOTH_IMAGE ) == BST_CHECKED;
g_DemoTypeUserDriven = IsDlgButtonChecked( g_OptionsTabs[DEMOTYPE_PAGE].hPage, IDC_DEMOTYPE_USER_DRIVEN ) == BST_CHECKED; g_DemoTypeUserDriven = IsDlgButtonChecked( g_OptionsTabs[DEMOTYPE_PAGE].hPage, IDC_DEMOTYPE_USER_DRIVEN ) == BST_CHECKED;
newToggleKey = static_cast<DWORD>(SendMessage( GetDlgItem( g_OptionsTabs[ZOOM_PAGE].hPage, IDC_HOTKEY), HKM_GETHOTKEY, 0, 0 )); newToggleKey = static_cast<DWORD>(SendMessage( GetDlgItem( g_OptionsTabs[ZOOM_PAGE].hPage, IDC_HOTKEY), HKM_GETHOTKEY, 0, 0 ));
@@ -2723,7 +2735,6 @@ VOID DrawShape( DWORD Shape, HDC hDc, RECT *Rect, bool UseGdiPlus = false )
bool isBlur = false; bool isBlur = false;
Gdiplus::Graphics dstGraphics(hDc); Gdiplus::Graphics dstGraphics(hDc);
if( ( GetWindowLong( g_hWndMain, GWL_EXSTYLE ) & WS_EX_LAYERED ) == 0 ) if( ( GetWindowLong( g_hWndMain, GWL_EXSTYLE ) & WS_EX_LAYERED ) == 0 )
{ {
dstGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); dstGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
@@ -2746,6 +2757,7 @@ VOID DrawShape( DWORD Shape, HDC hDc, RECT *Rect, bool UseGdiPlus = false )
InflateRect(Rect, g_PenWidth / 2, g_PenWidth / 2); InflateRect(Rect, g_PenWidth / 2, g_PenWidth / 2);
isBlur = true; isBlur = true;
} }
OutputDebug(L"Draw shape: highlight: %d pbrush: %d\n", PEN_COLOR_HIGHLIGHT(g_PenColor), pBrush != NULL);
switch (Shape) { switch (Shape) {
case DRAW_RECTANGLE: case DRAW_RECTANGLE:
@@ -2920,7 +2932,7 @@ void InvalidateCursorMoveArea( HWND hWnd, float zoomLevel, int width, int height
{ {
int x, y; int x, y;
RECT rc; RECT rc;
int invWidth = g_PenWidth; int invWidth = g_PenWidth + CURSOR_SAVE_MARGIN;
if( DrawHighlightedCursor( zoomLevel, width, height ) ) { if( DrawHighlightedCursor( zoomLevel, width, height ) ) {
@@ -2945,7 +2957,7 @@ void InvalidateCursorMoveArea( HWND hWnd, float zoomLevel, int width, int height
void SaveCursorArea( HDC hDcTarget, HDC hDcSource, POINT pt ) void SaveCursorArea( HDC hDcTarget, HDC hDcSource, POINT pt )
{ {
OutputDebug( L"SaveCursorArea\n"); OutputDebug( L"SaveCursorArea\n");
int penWidth = g_PenWidth + 2; int penWidth = g_PenWidth + CURSOR_SAVE_MARGIN;
BitBlt( hDcTarget, 0, 0, penWidth +CURSOR_ARM_LENGTH*2, penWidth +CURSOR_ARM_LENGTH*2, BitBlt( hDcTarget, 0, 0, penWidth +CURSOR_ARM_LENGTH*2, penWidth +CURSOR_ARM_LENGTH*2,
hDcSource, static_cast<INT> (pt.x- penWidth /2)-CURSOR_ARM_LENGTH, hDcSource, static_cast<INT> (pt.x- penWidth /2)-CURSOR_ARM_LENGTH,
static_cast<INT>(pt.y- penWidth /2)-CURSOR_ARM_LENGTH, SRCCOPY|CAPTUREBLT ); static_cast<INT>(pt.y- penWidth /2)-CURSOR_ARM_LENGTH, SRCCOPY|CAPTUREBLT );
@@ -2959,7 +2971,7 @@ void SaveCursorArea( HDC hDcTarget, HDC hDcSource, POINT pt )
void RestoreCursorArea( HDC hDcTarget, HDC hDcSource, POINT pt ) void RestoreCursorArea( HDC hDcTarget, HDC hDcSource, POINT pt )
{ {
OutputDebug( L"RestoreCursorArea\n"); OutputDebug( L"RestoreCursorArea\n");
int penWidth = g_PenWidth + 2; int penWidth = g_PenWidth + CURSOR_SAVE_MARGIN;
BitBlt( hDcTarget, static_cast<INT>(pt.x- penWidth /2)-CURSOR_ARM_LENGTH, BitBlt( hDcTarget, static_cast<INT>(pt.x- penWidth /2)-CURSOR_ARM_LENGTH,
static_cast<INT>(pt.y- penWidth /2)-CURSOR_ARM_LENGTH, penWidth +CURSOR_ARM_LENGTH*2, static_cast<INT>(pt.y- penWidth /2)-CURSOR_ARM_LENGTH, penWidth +CURSOR_ARM_LENGTH*2,
penWidth + CURSOR_ARM_LENGTH*2, hDcSource, 0, 0, SRCCOPY|CAPTUREBLT ); penWidth + CURSOR_ARM_LENGTH*2, hDcSource, 0, 0, SRCCOPY|CAPTUREBLT );
@@ -4178,6 +4190,11 @@ LRESULT APIENTRY MainWndProc(
} }
#endif #endif
} }
OutputDebug(L"LIVEDRAW SMOOTHING: %d\n", g_SmoothImage);
if (!pMagSetLensUseBitmapSmoothing(g_hWndLiveZoomMag, g_SmoothImage))
{
OutputDebug(L"MagSetLensUseBitmapSmoothing failed: %d\n", GetLastError());
}
if ( g_RecordToggle ) if ( g_RecordToggle )
{ {
@@ -5296,6 +5313,8 @@ LRESULT APIENTRY MainWndProc(
if( g_Drawing ) { if( g_Drawing ) {
OutputDebug(L"Mousemove: Drawing\n");
POINT currentPt; POINT currentPt;
// Are we in pen mode on a tablet? // Are we in pen mode on a tablet?
@@ -5334,7 +5353,15 @@ LRESULT APIENTRY MainWndProc(
} }
else else
{ {
DrawShape( g_DrawingShape, hdcScreenCompat, &g_rcRectangle ); if (PEN_COLOR_HIGHLIGHT(g_PenColor))
{
// copy original bitmap to screen bitmap to erase previous highlight
BitBlt(hdcScreenCompat, 0, 0, bmp.bmWidth, bmp.bmHeight, drawUndoList->hDc, 0, 0, SRCCOPY | CAPTUREBLT);
}
else
{
DrawShape(g_DrawingShape, hdcScreenCompat, &g_rcRectangle, PEN_COLOR_HIGHLIGHT(g_PenColor));
}
} }
} }
@@ -5380,7 +5407,7 @@ LRESULT APIENTRY MainWndProc(
g_rcRectangle.top != g_rcRectangle.bottom) { g_rcRectangle.top != g_rcRectangle.bottom) {
// Draw the new target rectangle. // Draw the new target rectangle.
DrawShape(g_DrawingShape, hdcScreenCompat, &g_rcRectangle); DrawShape(g_DrawingShape, hdcScreenCompat, &g_rcRectangle, PEN_COLOR_HIGHLIGHT(g_PenColor));
OutputDebug(L"SHAPE: (%d, %d) - (%d, %d)\n", g_rcRectangle.left, g_rcRectangle.top, OutputDebug(L"SHAPE: (%d, %d) - (%d, %d)\n", g_rcRectangle.left, g_rcRectangle.top,
g_rcRectangle.right, g_rcRectangle.bottom); g_rcRectangle.right, g_rcRectangle.bottom);
} }
@@ -5418,9 +5445,6 @@ LRESULT APIENTRY MainWndProc(
Gdiplus::BitmapData* lineData = LockGdiPlusBitmap(lineBitmap); Gdiplus::BitmapData* lineData = LockGdiPlusBitmap(lineBitmap);
BYTE* pPixels = static_cast<BYTE*>(lineData->Scan0); BYTE* pPixels = static_cast<BYTE*>(lineData->Scan0);
// Copy the contents of the screen bitmap to the temporary bitmap
GetOldestUndo(drawUndoList);
// Create a GDI bitmap that's the size of the lineBounds rectangle // Create a GDI bitmap that's the size of the lineBounds rectangle
Gdiplus::Bitmap *blurBitmap = CreateGdiplusBitmap( hdcScreenCompat, // oldestUndo->hDc, Gdiplus::Bitmap *blurBitmap = CreateGdiplusBitmap( hdcScreenCompat, // oldestUndo->hDc,
lineBounds.X, lineBounds.Y, lineBounds.Width, lineBounds.Height); lineBounds.X, lineBounds.Y, lineBounds.Width, lineBounds.Height);
@@ -5445,6 +5469,8 @@ LRESULT APIENTRY MainWndProc(
} }
else if(PEN_COLOR_HIGHLIGHT(g_PenColor)) { else if(PEN_COLOR_HIGHLIGHT(g_PenColor)) {
OutputDebug(L"HIGHLIGHT\n");
// This is a highlighting pen color // This is a highlighting pen color
Gdiplus::Rect lineBounds = GetLineBounds(prevPt, currentPt, g_PenWidth); Gdiplus::Rect lineBounds = GetLineBounds(prevPt, currentPt, g_PenWidth);
Gdiplus::Bitmap* lineBitmap = DrawBitmapLine(lineBounds, prevPt, currentPt, &pen); Gdiplus::Bitmap* lineBitmap = DrawBitmapLine(lineBounds, prevPt, currentPt, &pen);
@@ -5784,7 +5810,10 @@ LRESULT APIENTRY MainWndProc(
if( !g_DrawingShape ) { if( !g_DrawingShape ) {
// If the point has changed, draw a line to it // If the point has changed, draw a line to it
if (prevPt.x != LOWORD(lParam) || prevPt.y != HIWORD(lParam)) { if (!PEN_COLOR_HIGHLIGHT(g_PenColor))
{
if (prevPt.x != LOWORD(lParam) || prevPt.y != HIWORD(lParam))
{
Gdiplus::Graphics dstGraphics(hdcScreenCompat); Gdiplus::Graphics dstGraphics(hdcScreenCompat);
if ((GetWindowLong(g_hWndMain, GWL_EXSTYLE) & WS_EX_LAYERED) == 0) if ((GetWindowLong(g_hWndMain, GWL_EXSTYLE) & WS_EX_LAYERED) == 0)
{ {
@@ -5798,12 +5827,13 @@ LRESULT APIENTRY MainWndProc(
dstGraphics.DrawPath(&pen, &path); dstGraphics.DrawPath(&pen, &path);
} }
// Draw a dot at the current point, if the point hasn't changed // Draw a dot at the current point, if the point hasn't changed
else { else
{
MoveToEx(hdcScreenCompat, prevPt.x, prevPt.y, NULL); MoveToEx(hdcScreenCompat, prevPt.x, prevPt.y, NULL);
LineTo(hdcScreenCompat, LOWORD(lParam), HIWORD(lParam)); LineTo(hdcScreenCompat, LOWORD(lParam), HIWORD(lParam));
InvalidateRect(hWnd, NULL, FALSE); InvalidateRect(hWnd, NULL, FALSE);
} }
}
prevPt.x = LOWORD( lParam ); prevPt.x = LOWORD( lParam );
prevPt.y = HIWORD( lParam ); prevPt.y = HIWORD( lParam );
@@ -5818,8 +5848,11 @@ LRESULT APIENTRY MainWndProc(
g_rcRectangle.left != g_rcRectangle.right ) { g_rcRectangle.left != g_rcRectangle.right ) {
// erase previous // erase previous
if (!PEN_COLOR_HIGHLIGHT(g_PenColor))
{
SetROP2(hdcScreenCompat, R2_NOTXORPEN); SetROP2(hdcScreenCompat, R2_NOTXORPEN);
DrawShape(g_DrawingShape, hdcScreenCompat, &g_rcRectangle); DrawShape(g_DrawingShape, hdcScreenCompat, &g_rcRectangle);
}
// Draw the final shape // Draw the final shape
HBRUSH hBrush = static_cast<HBRUSH>(GetStockObject( NULL_BRUSH )); HBRUSH hBrush = static_cast<HBRUSH>(GetStockObject( NULL_BRUSH ));
@@ -6185,8 +6218,14 @@ LRESULT APIENTRY MainWndProc(
SetStretchBltMode( hInterimSaveDc, HALFTONE ); SetStretchBltMode( hInterimSaveDc, HALFTONE );
SetStretchBltMode( hSaveDc, HALFTONE ); SetStretchBltMode( hSaveDc, HALFTONE );
#else #else
// Use HALFTONE for better quality when smooth image is enabled
if (g_SmoothImage) {
SetStretchBltMode( hInterimSaveDc, HALFTONE );
SetStretchBltMode( hSaveDc, HALFTONE );
} else {
SetStretchBltMode( hInterimSaveDc, COLORONCOLOR ); SetStretchBltMode( hInterimSaveDc, COLORONCOLOR );
SetStretchBltMode( hSaveDc, COLORONCOLOR ); SetStretchBltMode( hSaveDc, COLORONCOLOR );
}
#endif #endif
StretchBlt( hInterimSaveDc, StretchBlt( hInterimSaveDc,
0, 0, 0, 0,
@@ -6309,7 +6348,12 @@ LRESULT APIENTRY MainWndProc(
#if SCALE_HALFTONE #if SCALE_HALFTONE
SetStretchBltMode( hSaveDc, HALFTONE ); SetStretchBltMode( hSaveDc, HALFTONE );
#else #else
// Use HALFTONE for better quality when smooth image is enabled
if (g_SmoothImage) {
SetStretchBltMode( hSaveDc, HALFTONE );
} else {
SetStretchBltMode( hSaveDc, COLORONCOLOR ); SetStretchBltMode( hSaveDc, COLORONCOLOR );
}
#endif #endif
StretchBlt( hSaveDc, StretchBlt( hSaveDc,
0, 0, 0, 0,
@@ -6646,8 +6690,8 @@ LRESULT APIENTRY MainWndProc(
(float)x, (float)y, (float)x, (float)y,
width/zoomLevel, height/zoomLevel ); width/zoomLevel, height/zoomLevel );
} else { } else {
// do a fast, less accurate render // do a fast, less accurate render (but use smooth if enabled)
SetStretchBltMode( hDc, HALFTONE ); SetStretchBltMode( hDc, g_SmoothImage ? HALFTONE : COLORONCOLOR );
StretchBlt( ps.hdc, StretchBlt( ps.hdc,
0, 0, 0, 0,
bmp.bmWidth, bmp.bmHeight, bmp.bmWidth, bmp.bmHeight,
@@ -6660,7 +6704,12 @@ LRESULT APIENTRY MainWndProc(
#if SCALE_HALFTONE #if SCALE_HALFTONE
SetStretchBltMode( hDc, zoomLevel == zoomTelescopeTarget ? HALFTONE : COLORONCOLOR ); SetStretchBltMode( hDc, zoomLevel == zoomTelescopeTarget ? HALFTONE : COLORONCOLOR );
#else #else
// Use HALFTONE for better quality when smooth image is enabled
if (g_SmoothImage) {
SetStretchBltMode( hDc, HALFTONE );
} else {
SetStretchBltMode( hDc, COLORONCOLOR ); SetStretchBltMode( hDc, COLORONCOLOR );
}
#endif #endif
StretchBlt( ps.hdc, StretchBlt( ps.hdc,
0, 0, 0, 0,
@@ -6683,7 +6732,7 @@ LRESULT APIENTRY MainWndProc(
BITMAP local_bmp; BITMAP local_bmp;
GetObject(g_hBackgroundBmp, sizeof(local_bmp), &local_bmp); GetObject(g_hBackgroundBmp, sizeof(local_bmp), &local_bmp);
SetStretchBltMode( hdcScreenCompat, HALFTONE ); SetStretchBltMode( hdcScreenCompat, g_SmoothImage ? HALFTONE : COLORONCOLOR );
if( g_BreakBackgroundStretch ) { if( g_BreakBackgroundStretch ) {
StretchBlt( hdcScreenCompat, 0, 0, width, height, StretchBlt( hdcScreenCompat, 0, 0, width, height,
g_hDcBackgroundFile, 0, 0, local_bmp.bmWidth, local_bmp.bmHeight, SRCCOPY|CAPTUREBLT ); g_hDcBackgroundFile, 0, 0, local_bmp.bmWidth, local_bmp.bmHeight, SRCCOPY|CAPTUREBLT );
@@ -6842,7 +6891,6 @@ LRESULT CALLBACK LiveZoomWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
WS_CHILD | MS_SHOWMAGNIFIEDCURSOR | WS_VISIBLE, WS_CHILD | MS_SHOWMAGNIFIEDCURSOR | WS_VISIBLE,
0, 0, 0, 0, hWnd, NULL, g_hInstance, NULL ); 0, 0, 0, 0, hWnd, NULL, g_hInstance, NULL );
} }
ShowWindow( hWnd, SW_SHOW ); ShowWindow( hWnd, SW_SHOW );
InvalidateRect( g_hWndLiveZoomMag, NULL, TRUE ); InvalidateRect( g_hWndLiveZoomMag, NULL, TRUE );
@@ -7555,6 +7603,10 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
"MagSetWindowTransform" ); "MagSetWindowTransform" );
pMagSetFullscreenTransform = (type_pMagSetFullscreenTransform)GetProcAddress(LoadLibrarySafe(L"magnification.dll", DLL_LOAD_LOCATION_SYSTEM), pMagSetFullscreenTransform = (type_pMagSetFullscreenTransform)GetProcAddress(LoadLibrarySafe(L"magnification.dll", DLL_LOAD_LOCATION_SYSTEM),
"MagSetFullscreenTransform"); "MagSetFullscreenTransform");
pMagSetFullscreenUseBitmapSmoothing = (type_MagSetFullscreenUseBitmapSmoothing)GetProcAddress(LoadLibrarySafe(L"magnification.dll", DLL_LOAD_LOCATION_SYSTEM),
"MagSetFullscreenUseBitmapSmoothing");
pMagSetLensUseBitmapSmoothing = (type_pMagSetLensUseBitmapSmoothing)GetProcAddress(LoadLibrarySafe(L"magnification.dll", DLL_LOAD_LOCATION_SYSTEM),
"MagSetLensUseBitmapSmoothing");
pMagSetInputTransform = (type_pMagSetInputTransform)GetProcAddress(LoadLibrarySafe(L"magnification.dll", DLL_LOAD_LOCATION_SYSTEM), pMagSetInputTransform = (type_pMagSetInputTransform)GetProcAddress(LoadLibrarySafe(L"magnification.dll", DLL_LOAD_LOCATION_SYSTEM),
"MagSetInputTransform"); "MagSetInputTransform");
pMagShowSystemCursor = (type_pMagShowSystemCursor)GetProcAddress(LoadLibrarySafe(L"magnification.dll", DLL_LOAD_LOCATION_SYSTEM), pMagShowSystemCursor = (type_pMagShowSystemCursor)GetProcAddress(LoadLibrarySafe(L"magnification.dll", DLL_LOAD_LOCATION_SYSTEM),

View File

@@ -95,6 +95,7 @@
#define IDC_COPYRIGHT 1075 #define IDC_COPYRIGHT 1075
#define IDC_PEN_WIDTH 1105 #define IDC_PEN_WIDTH 1105
#define IDC_TIMER 1106 #define IDC_TIMER 1106
#define IDC_SMOOTH_IMAGE 1107
#define IDC_SAVE 40002 #define IDC_SAVE 40002
#define IDC_COPY 40004 #define IDC_COPY 40004
#define IDC_RECORD 40006 #define IDC_RECORD 40006
@@ -109,7 +110,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 118 #define _APS_NEXT_RESOURCE_VALUE 118
#define _APS_NEXT_COMMAND_VALUE 40013 #define _APS_NEXT_COMMAND_VALUE 40013
#define _APS_NEXT_CONTROL_VALUE 1076 #define _APS_NEXT_CONTROL_VALUE 1078
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif

View File

@@ -81,6 +81,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonPropertyName("AnimnateZoom")] [JsonPropertyName("AnimnateZoom")]
public BoolProperty AnimateZoom { get; set; } public BoolProperty AnimateZoom { get; set; }
public BoolProperty SmoothImage { get; set; }
public IntProperty ZoominSliderLevel { get; set; } public IntProperty ZoominSliderLevel { get; set; }
public IntProperty RecordScaling { get; set; } public IntProperty RecordScaling { get; set; }

View File

@@ -54,6 +54,9 @@
<tkcontrols:SettingsCard Name="ZoomItToggleAnimateZoom" x:Uid="ZoomIt_Toggle_AnimateZoom"> <tkcontrols:SettingsCard Name="ZoomItToggleAnimateZoom" x:Uid="ZoomIt_Toggle_AnimateZoom">
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.AnimateZoom, Mode=TwoWay}" /> <ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.AnimateZoom, Mode=TwoWay}" />
</tkcontrols:SettingsCard> </tkcontrols:SettingsCard>
<tkcontrols:SettingsCard Name="ZoomItSmoothZoomedImage" x:Uid="ZoomIt_Toggle_SmoothZoomedImage">
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.SmoothImage, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard Name="ZoomItSliderInitialMagnification" x:Uid="ZoomIt_Slider_InitialMagnification"> <tkcontrols:SettingsCard Name="ZoomItSliderInitialMagnification" x:Uid="ZoomIt_Slider_InitialMagnification">
<Slider <Slider
MinWidth="{StaticResource SettingActionControlMinWidth}" MinWidth="{StaticResource SettingActionControlMinWidth}"

View File

@@ -4662,6 +4662,9 @@ Copy a zoomed screen with Ctrl+C or save it by typing Ctrl+S. Crop the copy or s
<data name="ZoomIt_Toggle_AnimateZoom.Header" xml:space="preserve"> <data name="ZoomIt_Toggle_AnimateZoom.Header" xml:space="preserve">
<value>Animate zoom in and zoom out</value> <value>Animate zoom in and zoom out</value>
</data> </data>
<data name="ZoomIt_Toggle_SmoothZoomedImage.Header" xml:space="preserve">
<value>Smooth zoomed image</value>
</data>
<data name="ZoomIt_Slider_InitialMagnification.Header" xml:space="preserve"> <data name="ZoomIt_Slider_InitialMagnification.Header" xml:space="preserve">
<value>Specify the initial level of magnification when zooming in</value> <value>Specify the initial level of magnification when zooming in</value>
</data> </data>

View File

@@ -197,6 +197,20 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
} }
} }
public bool SmoothImage
{
get => _zoomItSettings.Properties.SmoothImage.Value;
set
{
if (_zoomItSettings.Properties.SmoothImage.Value != value)
{
_zoomItSettings.Properties.SmoothImage.Value = value;
OnPropertyChanged(nameof(SmoothImage));
NotifySettingsChanged();
}
}
}
public int ZoominSliderLevel public int ZoominSliderLevel
{ {
get => _zoomItSettings.Properties.ZoominSliderLevel.Value; get => _zoomItSettings.Properties.ZoominSliderLevel.Value;