Determine the size of a checkbox at arbitrary dpi on windows 10 - c++

See here: How to get size of check and gap in check box?
It does not seem to quite answer the question as it applies to DPI.
I have tried several methods, but none yield the results of actual drawn checkboxes at various scale choices in Windows 10. The closest is
12 * GetDeviceCaps (LOGPIXELSX) / 96 + 1
This yields 22 pixels # 168 DPI, however, but Windows draws a 20 pixel checkbox.
Is there a reliable way to determine this? Below is a grid of results I captured, with greens being those that match the "on screen" values.

Related

Incorrect metrics and sizes of font created by CreateFont()

I trying to render a font into bitmap using WinAPI, but I can't reach needed sizes of font.
Here's how the font is initialized:
HDC dc = ::CreateCompatibleDC(NULL);
::SetMapMode(dc, MM_TEXT);
::SetTextAlign(dc, TA_LEFT | TA_TOP | TA_UPDATECP);
int size_in_pixels = 18;
HFONT font = ::CreateFontA(-size_in_pixels, ..., "Arial");
::SelectObject(dc, font);
::TEXTMETRICW tm = { 0 };
GetTextMetricsW(dc, &tm);
But after it I getting incorrect values both in GetGlyphOutlineW and GetTextMetricsW, it's not size I passed as parameter
I know that it's expecting value in logical units, but in MM_TEXT 1 unit should be 1 pixel, don't it?
I expecting that CreateFontA accepting point size when I passing a negative value (like here https://i.stack.imgur.com/tEt8J.png), but in fact it's wrong.
I tried bruteforcing values, and find out proper parameter for a few sizes:
18px = -19; 36px = -39; 73px = -78;
Also I tried formula that provided by Microsoft:
nHeight = -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
But it's also giving me a wrong result, rendered text (using GetGlyphOutlineW) is larger if measure it (for example height of 'j' should have exact size that I passed)
Also metrics from GetTextMetricsW are wrong, for example tmAscent. I know that on Windows it's including internal leading, but even if subtract tmInternalLeading from tmAscent it's still incorrect.
By the way, values from GetCharABCWidthsW are correct, so a+b+c is width of glyph in pixels (while documentation says it should be in logical units).
Also I should say about DPI, usually I using 125% on Windows 10 scale in settings, but I tried even with 100%, interesting that ::GetDeviceCaps(dc, LOGPIXELSY) not changing with scale I using, it's always 96
Here's example of CreateFontA(-128, ...) with final atlas and metrics:
rendered atlas
Question #1: What should I do to pass wanted point size in pixels and receive glyphs in proper size with correct metrics in pixels?
Question #2: What the strange units all these functions are using?
When you use ::SetMapMode(dc, MM_TEXT); the font size is specified in device pixels. Negative value excludes internal leading, so for the same absolute value the negative ones produce visually bigger fonts. If you want to get same height from GetTextExtentPoint32 for different fonts, use positive values.
In your example with -128 height, you are requesting font for which, after internal leading exclusion, height is 128 pixels. Font mapper selects 143 which is correct for internal leading of 15 pixels (128+15=143). tmAscent + tmDescent are also correct (115+28=143). You get what you specified.
You should take into account that values in text metric don't state hard bounds. Designer can design fonts so its glyphs sometimes go beyond guiding lines or don't reach them.
for example height of 'j' should have exact size that I passed
Dot over j can go beyond or not reach top line if designer finds it visually plausible to design it that way.
interesting that ::GetDeviceCaps(dc, LOGPIXELSY) not changing with scale I using, it's always 96
Unless you log off and log in, system DPI doesn't change. For per monitor DPI aware application you have to get DPI from monitor parameters or cache value given by WM_DPICHANGED.
Question #1: What should I do to pass wanted point size in pixels and receive glyphs in proper size with correct metrics in pixels?
I think you want to get specific distance between top and bottom lines and this is exactly how you create font HFONT font = ::CreateFontA(-size_in_pixels, ..., "Arial");. The problem lies in your assumption that font design lines are hard boundaries for each glyph, but font's designer don't have to strictly align glyphs to these lines. If you want glyphs strictly aligned, probably there is no way to get it. Maybe check different font.
Question #2: What the strange units all these functions are using?
When mode is set to WM_TEXT, raw device pixels are used. Positive height specifies height including tmInternalLeading, negative excludes it.
For positive value:
tmAscent + tmDescent = requestedHeight
For negative value:
tmAscent + tmDescent - tmInternalLeading = requestedHeight
Bellow I have pasted screen shots with different fonts showing that depending on selected font glyphs could be designed so they don't reach top line or go beyond it and bottom line in most cases also isn't reached.
Seems that for your requirements Arial Unicode MS would be better fit (but j still doesn't reach where you want it).
Arial:
Arial Unicode MS
Input Mono
Trebuched MS

Susy 2 - Debug image not correct - Not a sub-pixel rounding issue

Have a look at this Sassmeister and let me know where the extra darker blue column to the far right comes from please. I don't believe this is a sub-pixel rounding issue but something else.
What really confuses me is that the extra bit shows up with 12, 13 and 14 columns selected, but not with 10, 15 or 16 columns, though 12 columns means it is a full number.
1200 / 10 = 120
1200 / 12 = 100
1200 / 13 = 92.30769230769231
1200 / 14 = 85.71428571428571
1200 / 15 = 80
1200 / 16 = 75
So regardless of if the result is a full number or a fraction there is somewhat odd behavior of the debug image. I have also removed gutters to be sure it has nothing to do with those. The reason I believe this is not a sub-pixel rounding issue is that this extra bit varies in width when selecting different amounts of columns, best visible with 12 columns.
https://www.sassmeister.com/gist/39b8136d4dcc6b8acfd269f675c97af5
edit
The extra bit is not visible in latest Firefox, only shows up in Chrome, anyone have a fix for Chrome to display the debug image correctly?
This used to annoy me, just a chrome bug, debug img looks perfectly neat in FireFox.
Viewed in FireFox

Windows API - UI layout sizing/spacing guideline inconsistencies

I've been trying to make an application that follows the guidelines on layout as outlined here:
https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
I'm converting from DLUs to pixels using GetTextExtentPoint32 and my results are consistent with the ones found here:
http://metalkin.egloos.com/m/4269163
These results however are not consistent with the guidelines. A command button with a DLU size of 50 x 14 ends up being 75 x 26 in pixels instead of the 75 x 23 (73 x 21 plus a 1 pixel invisible border - a fairly common button size in windows applications, it seems) listed in the guidelines.
When using the DLU dimensions for text boxes there is too much padding below the text.
Am I missing something, or are the guidelines basically useless?

How to make printing the same on any printer?

Ive been using HORZRES and VERTRES to print various strings. I had been using xps to test my printing and such but when I switched over to my actually computer I noticed that things werent printing the same.
How do you get the size of the actual page and print from there?
For example if I was printing from a letter(8 1/2 x 12 inches) How could I get a universal measurement that could be used for any printer
You can use SetMapMode to change the mapping mode.
If you set the mapping mode to, say, MM_LOENGLISH then all drawing will be in units of 1/100 inch. A line drawn with length 100 will then be one inch long on any printer, and you don't need to worry about the printer's resolution.
If you want further information about the page you can get other data from GetDeviceCaps:
LOGPIXELSX - horizontal pixels per inch
LOGPIXELSY - vertical pixels per inch
PHYSICALWIDTH - width of the page in device units
PHYSICALHEIGHT - height of the page in device units
Then the width of the page in inches is PHYSICALWIDTH / LOGPIXELSX and the height is PHYSICALHEIGHT / LOGPIXELSY.

Poppler: render with a target resolution

I am writing a pdf viewer in Qt and C++ using Poppler. How can I render a pdf page to fit my widget size? Poppler provides a method named renderToImage which takes in a dpi and returns a QImage whose size varies with that dpi. How to calculate the right dpi?
pageSizeF() returns the page size in points, which divided by 72 gives you the page size in inches.
Each component of your widget size in pixels divided by each component of the size in inches gives you 2 dpi values (1 for each axis).
If you want to keep the page aspect ratio, you should pass the smaller of these two dpi values to renderToImage for both xres and yres parameters.