Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Tk screen and monitor size in mm, DPI and scaling

by Discipulus (Canon)
on Mar 12, 2021 at 08:42 UTC ( [id://11129491]=perlquestion: print w/replies, xml ) Need Help??

Discipulus has asked for the wisdom of the Perl Monks concerning the following question:

Hello folks!

I'm playing again with Tk and I needed to grab the screen size and I found how to do it in the Tk::Widget documentation. Unfortunately my eyes spotted the screenmmwidth method which aims to Returns a decimal string giving the width of $widget's screen, in millimeters

I found it interesting but also proved to give me erroneous results. I tested it with the following code:

use strict; use warnings; use Tk; my $mw = MainWindow->new(); my $name = $mw->screen; my $height = $mw->screenheight; my $width = $mw->screenwidth; my $scaling = $mw->scaling; my $heightmm = $mw->screenmmheight; my $widthmm = $mw->screenmmwidth; print <<EOT; screen name $name pixel width $width pixel height $height scaling $scaling mm width $widthmm mm height $heightmm EOT MainLoop;

The outputs on my win7 box is:

screen name :0.0 pixel width 1920 pixel height 1080 scaling 1.33333333333333 mm width 508 # <--- wrong! mm height 286 # <--- wrong!

Everything is correct but last two measures: infact the current monitor where the above mainwindow was displayed is (using the ruler) width 480mm height 270mm

tests

  • on win10 on a box where the monitor Scale and layout is set to 150% I get the above wrong value of 508 instead of 480 mm. If on a win10, you can check Scale and layout setting with new to me shortcut: explorer ms-settings:display
  • on a win7 box with a scaling factor of 100% I get the same wrong result of width 508 and the monitor is always the same, wide 480 mm.
  • on a VirtualBox Linux system, setting it to fullscreen, I also get the wrong value of 508 for the width. Also using xdpyinfo | grep 'dimensions:' I got dimensions:    1920x1080 pixels (508x286 millimeters)
To note that first and second test were run using a different pc so no the same graphical card was used.

Also to note that on the win10 box a powershell command (apparently not available in win7) gives correct measures:

Get-WmiObject -Namespace root\WMI -ComputerName localhost -Query "sel +ect InstanceName, MaxHorizontalImagesize, MaxVerticalImageSize from W +miMoninitorBasicDisplayParams" ... MaxHorizontalImageSize : 48 MaxVerticalImageSize : 27

UPDATE as vr noted below the above powershell code is mispelled: MaxvwerticalImageSize for MaxVerticalImageSize and now is corrected.

While investigating the issue I discovered that while GetSystemMetrics is available in perl via the Win32 module, in the meantime they invented the DPI Awareness Mode exposed by the call (not available in perl) GetSystemMetricsForDpi

I must also add that my desktop is configured as an extended one covering the big monitor and the laptop one but 508 is not correct anyway even adding the two monitors width.

Q1 - do you have back correct mm measures using the above perl code?

I'd like to know from you if you get correct mm measures from the above code and on which OS the test was run and with which eventual scaling effect applied.

Q2 - what about the $widget->scaling()?

The Tk::Widget documentation tell about the scaling and the dreadful DPI, 1/72 of inch and whatever:

> A ``point'' is a unit of measurement equal to 1/72 inch. A scaling factor of 1.0 corresponds to 1 pixel per point, which is equivalent to a standard 72 dpi monitor. A scaling factor of 1.25 would mean 1.25 pixels per point, which is the setting for a 90 dpi monitor; setting the scaling factor to 1.25 on a 72 dpi monitor would cause everything in the application to be displayed 1.25 times as large as normal.

Everywhere in my tests I got back a scaling factor of 1.3333333 and if I understand it correctly it means I have 1.33333 points every 1/72 of an inch ( 0,35277777777777775 mm). Again: if I do: total pixels / $widget->scaling() * 0,35277777777777775 I get back my, wrong 508

So: might be this scaling value the root cause of the wrong results I get? It is possible to get a correct meausre?

conclusions

Well.. I can live without mm measures using only pxels as I have ever done but I'm interested to see if there is a possibility to use screenmmwidth correctly.

In my new application I will disable mm measures by default and let the user able to enable it only using a command line switch and forcing them to read a big warning on screen and, obviously, documenting it.

Thanks for reading

L*

There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

Replies are listed 'Best First'.
Re: Tk screen and monitor size in mm, DPI and scaling
by Tux (Canon) on Mar 12, 2021 at 08:48 UTC

    Have you compared these results with what X11 gives you? (I know Windows is not X11 but you can have a simple X11 server by using something like MobaXterm on Windows).

    use strict; use warnings; eval { use X11::Protocol; # Screen dimensions my $x11 = X11::Protocol->new (); my $screen = ($ENV{DISPLAY}//":0.0") =~ m/\.(\d+)$/ ? $1 : 0; $x11->choose_screen ($screen); # Root window printf "Screen is %4d x %4d x %2d pixels (%3d x %3d mm) (X11)\n", $x11->{width_in_pixels}, $x11->{height_in_pixels}, $x11->{root +_depth}, $x11->{width_in_millimeters}, $x11->{height_in_millimeters}; }; eval { use Tk; my $mw = Tk::MainWindow->new; printf "Screen is %4d x %4d x %2d pixels (%3d x %3d mm) (Tk)\n", $mw->screenwidth, $mw->screenheight, $mw->depth, $mw->screenmmwidth, $mw->screenmmheight; };
    $ screen_size Screen is 3840 x 1200 x 24 pixels (1014 x 317 mm) (X11) Screen is 3840 x 1200 x 24 pixels (1014 x 317 mm) (Tk)

    Enjoy, Have FUN! H.Merijn
      Hello Tux and thanks,

      do you really have a monitor 1014 x 317 mm? Or you get wrong answers too?

      I tried with MobaXterm and I get other wrong results

      xdpyinfo | grep 'dimensions:' dimensions: 3840x1080 pixels (1016x286 millimeters)

      L*

      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

        I have two monitors where the desktop is stretched over both, so the dimension in pixels is correct. The dimension in mm is per definition wrong, as the pixels are not of the same size for both displays (I need to replace one of them).

        $ inxi | grep res resolution: 1: 1920x1080~60Hz 2: 1920x1200~60Hz $ xdpyinfo | grep dim dimensions: 3840x1200 pixels (1014x317 millimeters)

        Enjoy, Have FUN! H.Merijn
Re: Tk screen and monitor size in mm, DPI and scaling
by choroba (Cardinal) on Mar 12, 2021 at 09:02 UTC
    I'm on X11, both Tk and X11 give me the same numbers. The number are definitely wrong. Also, when I switch to a different monitor, which has the same resolution but a different size, the numbers stay the same.
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Tk screen and monitor size in mm, DPI and scaling
by vr (Curate) on Mar 13, 2021 at 06:44 UTC

    (508 mm == 20") is exactly 1920 px @ 96 dpi. Tk doesn't bother(*) to use "real" dpi of your display. The "1.3(3)" is result of default Windows (Linux) 96 dpi, i.e. 96/72 == 1.3(3).

    Scaling is both getter and setter, for those who strive to work in mm. It's simple math that links display diagonal, aspect ratio (i.e. WxH in pixels) and real resolution. For Linux, unlike other commands mentioned in this thread, the xrandr output matches the calculation of mm, and also ruler being applied :). For Windows, you have found PS command yourself (it's posted misspelled), result matches previous mm values for my double-boot config. I think the source for both platforms is parsing the EDID data, as e.g. Parse::EDID does.

    ---

    (*) Interesting, the fact that Tk's scaling is only approximately "1.3(3)" for some configurations (mine, too), makes me suspect that Tk doesn't set this parameter blindly, but some calculations involving e.g. display width, rounded to centimetres, are happening during start-up. I can think of good reasons for Tk to stick to "96 dpi", but they are speculations only.

      Thanks a lot vr for clarifications,

      > for those who strive to work in mm

      I think I will be no more in that number. it really seems too complicated to be sure of an exact measure in mm. It seems pixel are always accurate so I'll use pixels only.

      As always I must confess I make a lot of confusion with this matter and discovered about EDID today from your post. It seems EDID data in windows is concealed in the registry under HKLM\SYSTEM\CurrentControlSet\\Enum\DISPLAY\"name of your monitor"\Device Parameters\EDID key.

      I installed Parse::EDID and arranged the following:

      use strict; use warnings; use Parse::EDID; use Data::Dumper; # I have two similar keys: PHLC0E5 and PHL088B among many others. Bein +g the current monitor a Philips I guess it must be one of them. # I grabbed the relevant part of output of the command: # REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY\ +PHL088B\4&2afe7bec&0&UID50529024\Device Parameters" my $registry =<<EOT; 00FFFFFFFFFFFF00410CE5C0FE050000051A010380301B782AE7E5A5564DA1250F5054 +BD4B00D1C09500950FB30081 C0818001010101023A801871382D40582C4500DD0C1100001E000000FF005A51303136 +3035303031353334000000FC0050484C2032323745360A2020 20000000FD00384C1E5311000A202020202020013D EOT my $raw_edid = join'',split /\n/, $registry; my $edid = parse_edid( $raw_edid ); print Dumper $edid;

      The output is very verbose and glancing it I dont find any physical measure resembling those of my monitor: I read in the wikipedia article you linked, measures in centimeters are stored in bytes 21-22, but under which names in the following output? Again: my monitor is 48cm x 27cm

      If I understand you correctly I must figure which is the real current dpi value, modify the scaling accordingly and re-calculate the size in mm. Right?

      While this matter is interesting and thanking you for hints and time you spent on it, I'm considering to remove entirely the mm calculation from my application, leaving pixel as only option.

      L*

      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

        I think parse_edid expects raw binary, and

        my $raw_edid = pack 'H*', $registry;

        will work. There's also check_parsed_edid to alert you, even when (very) suspicious results failed to do so :).

        Looking at output, fractional dimensions, in mm, indicate something more involved than simply reading size in whole cm (bytes 21-22), I didn't investigate more closely. Further, I didn't investigate neither (sorry), if, after MainWindow-> scaling(X), anywhere where number for size (meaning 'pixels') is to be used, string such as "N.nm" (N.n mm) would result in identical rendering on screen (let's assume no rounding). That's the whole point of it all, to forget about 'pixels', if I'm reading what you say "re-calculate the size in mm" correctly. I agree, I'd probably won't follow this route, neither (not until all displays are 250 dpi or more).

Re: Tk screen and monitor size in mm, DPI and scaling
by kcott (Archbishop) on Mar 13, 2021 at 05:55 UTC

    G'day Discipulus,

    I don't believe I've ever used either of those mm methods; and I don't think I've used mm sizes for specifying widths, padding, etc. Except for character sizes for a few text-based widgets, I always gone with pixels. Anyway, I was curious and do seem to have a similar issue to what you describe. Here's the output from the test code you posted:

    screen name :0.0 pixel width 2560 pixel height 1440 scaling 1.33398982438864 mm width 677 mm height 381

    I have Perl 5.32 and Tk 804.035 running on a Cygwin/Win10 OS. The system (Win10 Settings) reports 2560x1440; I'm pretty sure that's accurate. The manufacturer's spec gives the monitor width as 27" — I wonder if that's the physical size (i.e. includes the housing surrounding the useable/viewable part of the screen).

    Those numbers would give me a DPI of 94.8148148148148 (2560/27); and, factoring in the scaling, a point size of 1/71.0761154855644" (not the expected 1/72").

    I don't know how the mm sizes are determined. I had a look in https://github.com/eserte/perl-tk/blob/master/Tk/Widget.pm but couldn't see anything useful there; it's probably hidden away in XS code somewhere.

    I also had a look in "Active bugs for Tk". I didn't see anything relevant but, with 140 outstanding issues, it's not impossible that I missed something. It may be worth raising a bug report.

    I don't use PowerShell but I do have it available. I tried your Get-WmiObject command, both as a normal user and as Administrator, and got the same error:

    PS C:\WINDOWS\system32> Get-WmiObject -Namespace root\WMI -ComputerNa +me localhost -Query "select InstanceName, MaxHorizontalImagesize, Max +vwerticalImageSize from WmiMoninitorBasicDisplayParams" Get-WmiObject : Invalid class "WmiMoninitorBasicDisplayParams" At line:1 char:1 + Get-WmiObject -Namespace root\WMI -ComputerName localhost -Query "s +e ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~ + CategoryInfo : InvalidType: (:) [Get-WmiObject], Manage +mentException + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.Powe +rShell.Commands.GetWmiObjectCommand

    I, too, was a little surprised at the scaling value. The system (Win10 Settings) reports scaling of 100%; not 133.398982438864%.

    — Ken

      Hello kcott and thanks for looking,

      the Tk scaling is not the windows scaling: you probably already read the vr's answer below. Is like Tk is assuming always a 96dpi settings while nowadays we are always running higher values.

      Me too I dont use powershell but was the only way I found to retrieve physical monitor size and does not works in win7. As vr noted, I had a typo in the powershell cut&paste and if you see above now I have fixed it. I dont use power(s)hell also because its totally unuseful errors (tell me if the error emitted is the relevant one.. ;)

      I love perl for its errors!

      L*

      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Tk screen and monitor size in mm, DPI and scaling ( Wx )
by Anonymous Monk on Mar 15, 2021 at 02:29 UTC

    I get same under Tk.pm and Tcl::Tk.pm

    screen name :0.0 pixel width 1024 pixel height 768 scaling 1.3330053300533 mm width 271 mm height 203 $ perl -MTcl::pTk::TkHijack pm11129491.pl screen name :0.0 pixel width 1024 pixel height 768 scaling 1.3330053300533 mm width 271 mm height 203

    screenmmheigh tracks to https://iweb.dl.sourceforge.net/project/tcl/Tcl/8.6.11/tk8.6.11.1-src.tar.gz

    $ ack -ri HeightMMOfScreen tk8.6.11 -B1 tk8.6.11\generic\tkCmds.c 843- WidthMMOfScreen(screenPtr) = width; 844: HeightMMOfScreen(screenPtr) = height; -- 1485- Tcl_SetObjResult(interp, 1486: Tcl_NewIntObj(HeightMMOfScreen(Tk_Screen(tkwin)))); tk8.6.11\unix\tkUnixEvent.c 201- } 202: if (HeightMMOfScreen(DefaultScreenOfDisplay(display)) <= 0) { -- 205- mm = HeightOfScreen(DefaultScreenOfDisplay(display)) * (25.4 / + 75.0); 206: HeightMMOfScreen(DefaultScreenOfDisplay(display)) = mm; tk8.6.11\xlib\X11\Xlib.h 115-#define WidthMMOfScreen(s) ((s)->mwidth) 116:#define HeightMMOfScreen(s) ((s)->mheight)

    I recognize that 25.4micron = 0.001 inch = 0.0254 mm

    #!/usr/bin/perl -- use strict; use warnings; use Wx(); my $name = Wx::Display->new->GetName; my $dc = Wx::ScreenDC->new; my( $width, $height ) = $dc->GetSizeWH ; my $scaling = ' ??? '; my $ppi = join ' x ', $dc->GetPPI->GetHeight, $dc->GetPPI->GetWidth; my( $widthmm , $heightmm ) = $dc->GetSizeMMWH(); print <<EOT; screen name $name pixel width $width pixel height $height scaling $scaling ppi $ppi mm width $widthmm mm height $heightmm EOT __END__ screen name \\.\DISPLAY1 pixel width 1024 pixel height 768 scaling ??? ppi 96 x 96 mm width 280 mm height 210

    The mm width/height seem close enough, the 7-9 mm difference could be the BLACK margin borders of my display. I recall adjusting margins on monitors years ago.

    As best I can tell with a ruler , not counting the black borders, my mm height is closer to 205mm , so neither tk 203 nor wx 210 are exact

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11129491]
Approved by haukex
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2024-04-20 07:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found