How to access screen display’s DPI settings via javascript? [duplicate]
Asked Answered
N

4

59

Is there a way to access the screen display's DPI settings in a Javascript function?

I am trying to position a HTML panel on the page and when the user's DPI is set to large (120), it throws the position off. I need to be able to know what the DPI is so I can adjust the position accordingly.

Neology answered 24/1, 2009 at 22:46 Comment(0)
P
38

Firstly, to help with the possible (and very common) confusion with the term DPI (dots per inch):

DPI isn't exactly a part of "display settings". It's (mis)used in two different contexts:

  1. The native pixels per inch of a display (or video). It determines how small the pixels are. You can have the same 1024x768 resolution on both a 14" laptop screen and a 17" LCD monitor. The former would roughly be 1280/14 = 91 DPI and the latter would roughly be 1280/17 = 75 DPI. The DPI of a screen is immutable; it can't be changed with display settings. More...
  2. The dots per inch painted on paper during printing. This is the number of side-by-side dots a printer/photocopier/fax machine can imprint within an inch of paper. Most printers can be set to print at a lower DPI, by just printing each dot as two, four, etc. dots. More...

When printing an image, there are many things that affect the final dimensions of the image on paper:

  • The dimensions of the source image -- this is the amount of pixels or data there is.
  • The DPI of the source image. This value determines how the dimensions should be interpreted when printing the image.
  • If the source image doesn't have embedded DPI information (a JPEG can have one, a GIF never does), the program that's being used may have settings to specify a DPI. This could be an image viewer/editor or even a web browser.
  • The zoom factor that's typically specified in a print dialog.
  • The current DPI setting of the printer.
  • The physical (max) DPI of the printer.

The bottom line is, the image that you're printing will effectively get resampled (reduced or enlarged) to match the final DPI that's used in the print process. Any of the parties involed may be causing this (the program, the print driver, the printer).

Now, coming back to your question. No, you can't determine the DPI of the screen, because it's not in software domain. It's a hardware domain term, describing how large a monitor a user could afford to buy. Update: I initially wrote this answer back in 2009, with my understanding of the current technologies. As @thure pointed out, you can now (since 2012?) use the window.matchMedia function to determine the DPI of the screen.

If you're trying to achieve precision in printing an HTML layout, as others have suggested, your CSS should use print dimensions like em, pt or pc instead of px. However, the final outcome might still depend on the browser using. If converting your HTML to PDF (or generating PDF from scratch) is an option for you, printing a PDF would give you the truest WYSIWYG both on screen and paper.

Prewitt answered 24/1, 2009 at 22:46 Comment(11)
Although you can't change the physical DPI, you can change the software which maps measurements to pixels, which is governed by software, which, has a arbitrary value, usually probed from the monitor via EDID, but can be overridden. Which is what I think the OP was getting at.Hyalo
No, there are many cases where knowing physical properties like DPI and screen dimensions from software--including from as high a level as Javascript--is useful. API designers who don't expose something this obvious because they can't think of a case where it's needed must both lack foresight and have delusions of omniscience.Rustice
@Glenn Maynard: Yes, in fact, Android supports DIP (device-independent pixels) in its graphics API. The lower level rasterization library translates DIPs to actual pixels based on the known DPI of the screen.Prewitt
This answer is essentially wrong: "No, you can't determine the DPI of the screen, because it's not in software domain," is simply not true. You could use the matchMedia function or the screen object mentioned in @Ryan's answer.Benefactor
@thure I wasn't aware of a matchMedia function back in 2009 when I wrote this answer. The answer might be a bit outdated and thus become inaccurate today. I'll update it to mention the function. Thanks for raising this.Prewitt
Update: although matchMedia allows for querying dpi, most browsers will assume 96dpi regardless of the actual pixel density of the display.Benefactor
@thure, it's probably because browsers running on desktops have no way of knowing the screen DPI. There probably needs to be an OS-level facility for carrying this information (based on monitor driver, etc.) to the browser. I emphasize: Probably. I really haven't kept myself up-to-date with the offerings of modern OS APIs. Mobile phone browser can do this because it is easier to know the DPI of the phone screen (especially since people don't typically attach external displays to phones :)).Prewitt
@AtesGoral, I would guess the same, though apparently webkit and gecko know their "pixel density" via media queries, which is a similar metric to dpi - no idea where the user agents get that information, though.Benefactor
In short, currently there is no means to know the system dpi (72 or 96) and the screen resolution from within a browser using javascript. Is that correct?Allopathy
if (window.matchMedia("(min-resolution: 192dpi)").matches) console.log('matches!') works fine for me, I am using a 2 screen set up, if I run it on my macbook screen it prints 'matches!', but not if i drag the window over to my crappy old monitorWoorali
How are they doing this here and getting the size of the screen in inches and pixels: dpi.lvRoter
M
45

Looks like you can use the 'screen' DOM object in IE, its got properties for deviceXDPI, deviceYDPI, logicalXDPI, logicalYDPI.

https://www.w3schools.com/jsref/obj_screen.asp

Here's a solution from http://www.webdeveloper.com/forum/showthread.php?t=175278 (i havent tried it, seems like a total hack :) Just create something 1 inch wide and measure it in pixels!

console.log(document.getElementById("dpi").offsetHeight);
#dpi {
    height: 1in;
    left: -100%;
    position: absolute;
    top: -100%;
    width: 1in;
}
<div id="dpi"></div>
Mikol answered 8/5, 2009 at 8:14 Comment(10)
jsfiddle.net/AvVH4 has this code. It always returns 96 for me.Lycanthrope
This codes returns the "DPI setting" from Windows's display properties, i.e. 96="Normal size", 120="Large size", or other values for custom setting, such as 106="110% of normal size".Agha
Seems to work under MS Windows, but not on some mobile devices, see https://mcmap.net/q/81735/-detecting-the-system-dpi-ppi-from-js-css/698168Agha
Doesn't seem to be working. The jsfiddle returns 96 on my iPhone5S.Inlaid
It doesn't work. Don't do it. I just tried it on my test system with 200% DPI setting and neither IE nor Chrome reported it correctly. Both gave me 96.Fye
Take a look at this improved solution stackoverflow.com/a/26004882 which takes the devicePixelRatio in account. Worked for me.Candlenut
I think almost nobody targets IE, for it is always odd.Allopathy
Here, an inch is defined as 96 px, so no matter what your screen size/resolution it will always return 96.Inamorata
This is inaccurate. An in unit in CSS will always be 96 px on a screen, no matter the DPI. It's a unit only really useful for print. Source w3.org/Style/Examples/007/units.en.htmlSp
This does not work for meRoter
P
38

Firstly, to help with the possible (and very common) confusion with the term DPI (dots per inch):

DPI isn't exactly a part of "display settings". It's (mis)used in two different contexts:

  1. The native pixels per inch of a display (or video). It determines how small the pixels are. You can have the same 1024x768 resolution on both a 14" laptop screen and a 17" LCD monitor. The former would roughly be 1280/14 = 91 DPI and the latter would roughly be 1280/17 = 75 DPI. The DPI of a screen is immutable; it can't be changed with display settings. More...
  2. The dots per inch painted on paper during printing. This is the number of side-by-side dots a printer/photocopier/fax machine can imprint within an inch of paper. Most printers can be set to print at a lower DPI, by just printing each dot as two, four, etc. dots. More...

When printing an image, there are many things that affect the final dimensions of the image on paper:

  • The dimensions of the source image -- this is the amount of pixels or data there is.
  • The DPI of the source image. This value determines how the dimensions should be interpreted when printing the image.
  • If the source image doesn't have embedded DPI information (a JPEG can have one, a GIF never does), the program that's being used may have settings to specify a DPI. This could be an image viewer/editor or even a web browser.
  • The zoom factor that's typically specified in a print dialog.
  • The current DPI setting of the printer.
  • The physical (max) DPI of the printer.

The bottom line is, the image that you're printing will effectively get resampled (reduced or enlarged) to match the final DPI that's used in the print process. Any of the parties involed may be causing this (the program, the print driver, the printer).

Now, coming back to your question. No, you can't determine the DPI of the screen, because it's not in software domain. It's a hardware domain term, describing how large a monitor a user could afford to buy. Update: I initially wrote this answer back in 2009, with my understanding of the current technologies. As @thure pointed out, you can now (since 2012?) use the window.matchMedia function to determine the DPI of the screen.

If you're trying to achieve precision in printing an HTML layout, as others have suggested, your CSS should use print dimensions like em, pt or pc instead of px. However, the final outcome might still depend on the browser using. If converting your HTML to PDF (or generating PDF from scratch) is an option for you, printing a PDF would give you the truest WYSIWYG both on screen and paper.

Prewitt answered 24/1, 2009 at 22:46 Comment(11)
Although you can't change the physical DPI, you can change the software which maps measurements to pixels, which is governed by software, which, has a arbitrary value, usually probed from the monitor via EDID, but can be overridden. Which is what I think the OP was getting at.Hyalo
No, there are many cases where knowing physical properties like DPI and screen dimensions from software--including from as high a level as Javascript--is useful. API designers who don't expose something this obvious because they can't think of a case where it's needed must both lack foresight and have delusions of omniscience.Rustice
@Glenn Maynard: Yes, in fact, Android supports DIP (device-independent pixels) in its graphics API. The lower level rasterization library translates DIPs to actual pixels based on the known DPI of the screen.Prewitt
This answer is essentially wrong: "No, you can't determine the DPI of the screen, because it's not in software domain," is simply not true. You could use the matchMedia function or the screen object mentioned in @Ryan's answer.Benefactor
@thure I wasn't aware of a matchMedia function back in 2009 when I wrote this answer. The answer might be a bit outdated and thus become inaccurate today. I'll update it to mention the function. Thanks for raising this.Prewitt
Update: although matchMedia allows for querying dpi, most browsers will assume 96dpi regardless of the actual pixel density of the display.Benefactor
@thure, it's probably because browsers running on desktops have no way of knowing the screen DPI. There probably needs to be an OS-level facility for carrying this information (based on monitor driver, etc.) to the browser. I emphasize: Probably. I really haven't kept myself up-to-date with the offerings of modern OS APIs. Mobile phone browser can do this because it is easier to know the DPI of the phone screen (especially since people don't typically attach external displays to phones :)).Prewitt
@AtesGoral, I would guess the same, though apparently webkit and gecko know their "pixel density" via media queries, which is a similar metric to dpi - no idea where the user agents get that information, though.Benefactor
In short, currently there is no means to know the system dpi (72 or 96) and the screen resolution from within a browser using javascript. Is that correct?Allopathy
if (window.matchMedia("(min-resolution: 192dpi)").matches) console.log('matches!') works fine for me, I am using a 2 screen set up, if I run it on my macbook screen it prints 'matches!', but not if i drag the window over to my crappy old monitorWoorali
How are they doing this here and getting the size of the screen in inches and pixels: dpi.lvRoter
G
35

You might use the window.devicePixelRatio property to get the scaling ratio of the screen/page. This works well in current IE, Edge, Chrome and Firefox on the desktop (Windows), but it doesn't seem to be a current standard. It returns 1 on my desktop PC with a conventional monitor and 2 on the Surface with 200% scaling. Values should range from 1.0 to 3.0 these days. I could use this to correct dynamic image serving size to provide sharper images on high-resolution screens.

If you need some logical dpi/ppi, multiply that value with 96. It won't be the actual physical ppi though, just what the OS treats it like.

Girlie answered 2/6, 2016 at 20:51 Comment(2)
W3 specLowpressure
this is awesome. works for me.Byrnes
H
2

There isn't a way that I know of, however, they may be an alternative solution:

Specify your measurements in 'pt' and 'em', which are screen relative metrics.

http://www.w3schools.com/cssref/css_units.asp

https://css-tricks.com/the-lengths-of-css/

  • em:
    1em is equal to the current font size. 2em means 2 times the size of the current font. E.g., if an element is displayed with a font of 12 pt, then '2em' is 24 pt. The 'em' is a very useful unit in CSS, since it can adapt automatically to the font that the reader uses
  • pt:
    point (1 pt is the same as 1/72 inch)
  • pc:
    pica (1 pc is the same as 12 points)
Hyalo answered 25/1, 2009 at 1:18 Comment(2)
Try this one. w3schools.com/cssref/css_units.aspDedication
1pt = 1.33px and 1pc = 16px. Regardless of dpi, as browsers assume 1in = 96px, which is not real and incorrect...Babysitter

© 2022 - 2024 — McMap. All rights reserved.