I have a simple UserForm to prototype the concept of loading different sizes of the same image based on the Windows display scale that the user sets. For this example, I'm just testing with 100% scale (96DPI) and 200% scale (192DPI).
The source BMP images are as follows:
- 1x image is 500px by 500px
- 2x image is 1000px by 1000px
Using the 0.75 (72/96) pixel to points ratio, I've set an image control to 375pts wide by 375pts high and loaded the 1x BMP image. When I run the UserForm, the image renders at 500x500 pixels as expected at display scale 100%:
I then shut down the host Office app and change the display scale to 200% in system settings:
I restart the app (PowerPoint in my case) and this time load the 2x image into the same image control. When I run the UserForm, the image doesn't render at 1000x1000 pixels as I'd expect, but 1072x1072 pixels, complete with scaling artefacts:
I need to apply a fudge factor of 1000/1072 (0.933) to get the image control to render at the expected pixel size, without scaling artefacts:
I develop on a Parallels VM but have also tested the same behaviour on a Windows Surface machine.
Why is this happening?
Steps to reproduce:
Create a VBA project with a UserForm containing two image controls named Image1 and Image2x and set both to 375pts x 375pts with scale mode set to zoom.
Load a 500x500px BMP image into Image1 and a 1000x1000 BMP image into Image2x.
Add the code below and run the UserForm at display scales of 100% and 200%, restarting the host app between changes.
Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hdc As LongPtr, ByVal nIndex As Long) As Long Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hdc As LongPtr) As Long Private Const LOGPIXELSX = 88 Private Const LOGPIXELSY = 90 Private Sub UserForm_Initialize() Select Case GetDPIScale ' If the display scale is 200%, load the 2x image from the second image control and apply the fudge factor Case 2 With Me.Image1 .Picture = Me.Image2x.Picture .Width = .Width * 0.933 .Height = .Height * 0.933 End With End Select End Sub Private Function GetDPIScale() As Double Dim hdc As LongPtr Dim dpiX As Long hdc = GetDC(0) dpiX = GetDeviceCaps(hdc, LOGPIXELSX) ReleaseDC 0, hdc GetDPIScale = dpiX / 96 ' 96 DPI is standard baseline End Function
UPDATE:
I tested other sizes and the results are even stranger:




