Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed Program Icon Scaling for Multi Zoom #1709

Merged

Conversation

amartya4256
Copy link
Contributor

@amartya4256 amartya4256 commented Jan 7, 2025

In the previous implementation, according to the documentation, SHGetFileInfo retrieves a system icon at the primary monitor native zoom. It means if the primary monitor is 175%, the dimension of the icon will be 56 x 56 (considering the standard dimension of 16 x 16 at 100%). Previously, the Image::win32_new was used to create an image object by passing the handle. Since the support of multi zoom, we know that now an image can have multiple handles, each for a zoom level. Image::win32_new used to assign the handle to the image at DPIUtil::getDeviceZoom regarless of what zoom level the handle was created for (in our case primary monitor native zoom, e.g. 175%). And it used to do some calcultation what proportion of primary monitor zoom would be this assigned zoom of the image. In other words, if you wanna obtain an image for 100% zoom, it will be 57% of 175%. Since, it used to call image.getImageData(57), which kinda seems like a hack to obtain the icon with the right dimension.

Another problem that was quite visible was that if the monitor to draw the icon has a higher zoom level (say 300%) than the primary monitor zoom, the icon will be pixelated because the retrieved icon from SHGetFileInfo is 175% (primary montior native zoom)

This contribution reimplements the logic for scaling the Program Icons while getting rid of the DPIUtil::getDeviceZoom usage and enhancing the image quality of icons on scaling up using the Small Icon in case we have to scale down and using the Large Icon in case we have to scale up.

contributes to #62 and #127

Copy link
Contributor

github-actions bot commented Jan 7, 2025

Test Results

   494 files  ±0     494 suites  ±0   10m 36s ⏱️ +33s
 4 324 tests ±0   4 306 ✅ ±0   18 💤 ±0  0 ❌ ±0 
16 534 runs  ±0  16 386 ✅ ±0  148 💤 ±0  0 ❌ ±0 

Results for commit bacb660. ± Comparison against base commit 0fa596c.

♻️ This comment has been updated with latest results.

Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good to me. If I understand everything correctly, the change to Program makes total sense and the implementaton is far more clean and reasonable with the change than it was before.
I currently only have one comment regarding a change to Image, as from my understanding that change indicates an existing bug, independent from the changes to program icons, so I would propose to extract that one into a dedicated PR for that specific issue.

I have not tested the changes so far, but will do that as soon as possible.

Comment on lines 1365 to 1368
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
int currentZoom = getZoom();
if (zoom == currentZoom) {
return getImageDataAtCurrentZoom();
} else if (imageProvider != null) {
if (zoomLevelToImageHandle.get(zoom) != null) {
return zoomLevelToImageHandle.get(zoom).getImageData();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this something was wrong wrong anyway, independent from Program icons? Querying the image data for specific zoom value should not consider any autoscaling-value-based correction of that zoom value anyway, should it? So I think this change should be extracted into a separate PR with an according regression test, e.g., for autoscaling integer200 retrieving image data for zoom 125 and 150 one after another and assuming that they do not deliver the same image data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have adjusted the PR as per requested. Here's the PR for the Image::getImageData fix: #1713

@amartya4256 amartya4256 force-pushed the program_icon_scaling branch 3 times, most recently from 8fecf0b to 2b5e970 Compare January 9, 2025 15:14
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now also tested the change and have some findings. Some are expected and unavoidable with the current type of implementation whereas at least seems to be a regression.

Expected Limitations

Since the used Windows API methods return icons scaled according to the primary monitor, you will often have two scalings applied: first by Windows scaling one of the original 16x16, 32x32, ... icons to what is required for the zoom level of the primary monitor, and second, by the application to use it in the scaling required for the monitor the window is currently placed on.

This means for example means if your primary monitor has a rather high resolution (e.g., scaled at 200% or more), the icons for other, lower resolution monitors (e.g., at 100%) are scaled down dramatically, leading to information loss. E.g., at 200% primary zoom the large icon is loaded and scaled down to 100% for a 100% secondary monitor:
image

It even looks bad if you have an "ordinary" 100% monitor but the primary monitor has, e.g., 150% scaling on the 100%, for which you would expect the original 100% icons to be loaded:
image

Regression

Environment:

  • Single monitor sufficient
  • Primary monitor scaling 150%
  • Auto scale mode quarter

Original appearance:
image

Appearance with this PR:
image

You can see the information, in particular in the icons for PowerPoint and Excel documents. They become hardly comprehensible.
The reason is that the package explorer loads 200% images, thus making the new implementation retrieve the large icon, which is delivered at 300% (two times the native zoom) and then for final rendering scaled down to 150%.

Note that this effect was also covered in #1014. The following code has been used there to determine when to use large icons (note that comment and implementation are not aligned):

// Use small icon if expected icon size is less than 150% of delivered icon size
// and use large icon if it is more than 150% of the delivered icon size
boolean useLargeIcon = 100 * zoom /  primaryMonitorZoom > 200;

Maybe that's something to reuse.

@amartya4256 amartya4256 force-pushed the program_icon_scaling branch 2 times, most recently from 9746820 to 5a8a39a Compare January 13, 2025 13:50
@amartya4256
Copy link
Contributor Author

amartya4256 commented Jan 13, 2025

boolean useLargeIcon = 100 * zoom /  primaryMonitorZoom > 200;

boolean useLargeIcon = 100 * zoom / primaryMonitorZoom >= 200; did the job for me. with just ">", I could still see some blurry scaling in case of 100 as primary monitor and 200 as the other monitor
@HeikoKlare

@HeikoKlare HeikoKlare force-pushed the program_icon_scaling branch from 5a8a39a to 2f67eb2 Compare January 13, 2025 20:48
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change now looks sound to me and I did not find any issues while testing.

Could you please have a second look regarding the changes in the Image class, whether passing zoom to the win32_new method is also fine from your point of view, @akoch-yatta?

@akoch-yatta
Copy link
Contributor

The change now looks sound to me and I did not find any issues while testing.

Could you please have a second look regarding the changes in the Image class, whether passing zoom to the win32_new method is also fine from your point of view, @akoch-yatta?

Yes, this is the necessary here and probably even the better solution overall. Only thing to mention here, is that the passed some is different in some usages. The used zoom look correct, but we should be aware that there could be some regressions, if the zoom is wrong -> regression would "only" mean blurry scaling

@HeikoKlare
Copy link
Contributor

Only thing to mention here, is that the passed some is different in some usages. The used zoom look correct, but we should be aware that there could be some regressions, if the zoom is wrong -> regression would "only" mean blurry scaling

Yes, important point. I was also thinking about whether the actual passed zoom values are correct, but found them all to be reasonable. If I am not mistaken, only risk for regressions is in Program icons (which are actually to be improved by this PR) and in TaskBar. At all other places the zoom is retrieved via DPIUtil.getNativeDeviceZoom() just like within the image done now.

Another change affecting the zoom is that the ImageHandle is now created with nativeZoom instead of image.getZoom(), but from my understanding that just makes that line of code consistent with the changes in #1713.

@HeikoKlare HeikoKlare force-pushed the program_icon_scaling branch from 2f67eb2 to fd88c37 Compare January 15, 2025 09:36
This contribution reimplements the logic for scaling the Program Icons
while getting rid of the DPIUtil::getDeviceZoom usage and enhancing the image
quality of icons on scaling up.

contributes to eclipse-platform#62 and eclipse-platform#127
@HeikoKlare HeikoKlare force-pushed the program_icon_scaling branch from fd88c37 to bacb660 Compare January 15, 2025 11:02
@HeikoKlare HeikoKlare merged commit 9ee0370 into eclipse-platform:master Jan 15, 2025
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve dynamic scaling of external Program icons
3 participants