Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting the system DPI/PPI from JS/CSS?

People also ask

How do I know my PPI DPI?

If you know the PPI – again, let's say 300 – you divide the total dimensional pixels to determine the inches: 1920/300 = 6.4. 1080/300 = 3.6.

Is DPI same with PPI?

DPI refers to the number of printed dots contained within one inch of an image printed by a printer. PPI refers to the number of pixels contained within one inch of an image displayed on a computer monitor.

Is 300 PPI the same as DPI?

PPI refers to how many pixels per inch there are in a digital image. So, technically, it's PPI until you have a physically printed image, then it becomes DPI and vice versa. However, pixels and dots are pretty much interchangeable. A 300 PPI image will still be a 300 DPI image.


<div id='testdiv' style='height: 1in; left: -100%; position: absolute; top: -100%; width: 1in;'></div>
<script type='text/javascript'>
  var devicePixelRatio = window.devicePixelRatio || 1;
  dpi_x = document.getElementById('testdiv').offsetWidth * devicePixelRatio;
  dpi_y = document.getElementById('testdiv').offsetHeight * devicePixelRatio;
  
  console.log(dpi_x, dpi_y);
</script>

grabbed from here http://www.infobyip.com/detectmonitordpi.php. Works on mobile devices! (android 4.2.2 tested)


I came up with a way that doesn't require the DOM... at all

The DOM can be messy, requiring you to append stuff to the body without knowing what stuff is going on with width: x !important in your stylesheet. You would also have to wait for the DOM to be ready to use...

/**
 * Binary search for a max value without knowing the exact value, only that it can be under or over
 * It dose not test every number but instead looks for 1,2,4,8,16,32,64,128,96,95 to figure out that
 * you thought about #96 from 0-infinity
 *
 * @example findFirstPositive(x => matchMedia(`(max-resolution: ${x}dpi)`).matches)
 * @author Jimmy Wärting
 * @see {@link https://stackoverflow.com/a/35941703/1008999}
 * @param {function} fn       The function to run the test on (should return truthy or falsy values)
 * @param {number}   start=1  Where to start looking from
 * @param {function} _        (private)
 * @returns {number}          Intenger
 */
function findFirstPositive (f,b=1,d=(e,g,c)=>g<e?-1:0<f(c=e+g>>>1)?c==e||0>=f(c-1)?c:d(e,c-1):d(c+1,g)) {
  for (;0>=f(b);b<<=1);return d(b>>>1,b)|0
}

var dpi = findFirstPositive(x => matchMedia(`(max-resolution: ${x}dpi)`).matches)

console.log(dpi)

There is the resolution CSS media query — it allows you to limit CSS styles to specific resolutions:

  • http://www.w3.org/TR/css3-mediaqueries/#resolution

However, it’s only supported by Firefox 3.5 and above, Opera 9 and above, and IE 9. Other browsers won’t apply your resolution-specific styles at all (although I haven’t checked non-desktop browsers).


Here is what works for me (but didn't test it on mobile phones):

<body><div id="ppitest" style="width:1in;visible:hidden;padding:0px"></div></body>

Then I put in the .js: screenPPI = document.getElementById('ppitest').offsetWidth;

This got me 96, which corresponds to my system's ppi.


The reply from @Endless is pretty good, but not readable at all, this is a similar approche with fixed min/max (it should be good ones)

var dpi = (function () {
    for (var i = 56; i < 2000; i++) {
        if (matchMedia("(max-resolution: " + i + "dpi)").matches === true) {
            return i;
        }
    }
    return i;
})();

matchMedia is now well supported and should give good result, see http://caniuse.com/#feat=matchmedia

Be careful the browser won't give you the exact screen dpi but only an approximation


I also needed to display the same image at the same size at different screen dpi but only for Windows IE. I used:

<img src="image.jpg" style="
    height:expression(scale(438, 192)); 
    width:expression(scale(270, 192))" />

function scale(x, dpi) {

    // dpi is for orignal dimensions of the image
    return x * screen.deviceXDPI/dpi;
}

In this case the original image width/height are 270 and 438 and the image was developed on 192dpi screen. screen.deviceXDPI is not defined in Chrome and the scale function would need to be updated to support browsers other than IE


DPI is by definition tied to the physical size of the display. So you won't be able to have the real DPI without knowing exactly the hardware behind.

Modern OSes agreed on a common value in order to have compatible displays: 96 dpi. That's a shame but that's a fact.

You will have to rely on sniffing in order to be able to guess the real screen size needed to compute the resolution (DPI = PixelSize / ScreenSize).