get device PPI in javascript
Asked Answered
C

5

15

How to get real PPI (pixels per inch) device resolution with javascript?

some examples of device and value expected:

  • iMac 27-inch: 109ppi
  • iPad: 132ppi
  • 19inch 1440x900 screen: 89ppi
  • ...
Conlen answered 4/4, 2014 at 11:15 Comment(0)
C
13

Running a native application directly on top of the operating system is the only surefire way to acquire the physical characteristics of the client monitor stored in the EDID. No mainstream browser engine currently offers this information through any web API and will likely not in the foreseeable future. However there are several ways to approximate the density to varying levels of accuracy.

All modern browsers give hints to the pixel density via attributes like devicePixelRatio, deviceXDPI which basically tell you how much zoom the client has going on (versus 1.0x Operating System default zoom). If you're targeting only a few devices like the Apple line then you might be able to tell which one is which, although Apple doesn't leave a scrap of a clue to discern a iPad mini from a regular iPad.

Another alternative is using device databases or proprietary software that analyze the client's "user agent string" to achieve a hit-or-miss guess of the device and then looking up the DPI associated with that device if it exists in their big database. Expensive proprietary systems might have higher accuracy by leveraging complex data mining algorithms but regardless any system like this would need constant manual updating and will still remain open to client manipulation since they can just change their user agent string ("view this website in desktop mode")

It's really an unfortunate situation not having this information available. I've spent countless hours researching ANY POSSIBLE WAY to make a PPI aware Web Application.

Maybe one day someone will be able to convince the folks at WebKit or Mozilla or Microsoft to allow people to create PPI aware Web apps for augmented reality and such... Sigh

Chirr answered 17/4, 2014 at 8:56 Comment(5)
Is it also not possible with plugins ? (flash, java, sylverlight, ...)?Inexact
We not need to convince mozilla, google or microsoft but to propose a EDID api to W3CInexact
Unfortunately there's no functions in flash, java, or silverlight that let you access the OS's EDID information. They only offer you what relative zoom level is being applied.Chirr
Although using Java apps, it's possible to package in an OS specific JNI accessible library that fetches the EDID data. The problem then becomes the difficulty involved in deploying Java apps via a browser.Chirr
If what you do with the value is really useful to people, you could as well ask them to tell your App f.e. by scaling an element to exactly 1 cmTriliteral
D
5

In pure JS:

function calcScreenDPI() {
    const el = document.createElement('div');
    el.style = 'width: 1in;'
    document.body.appendChild(el);
    const dpi = el.offsetWidth;
    document.body.removeChild(el);

    return dpi;
}

console.log(calcScreenDPI());
Deceitful answered 4/8, 2019 at 11:29 Comment(2)
Always returns 96Honesty
Tested on a PC and high resolution mac retina display. They both return 96. I believe it is probably a browser standard, as if a retina display did convert a 100px wide element into the real pixel equivalent it would be absolutely tiny.Disrespectful
F
1

In a Chrome Extension

Related, but not an exact answer to the poster's question:

You can get the DPI of your display (and a lot of other information), if you're developing a Chrome Extension with the proper permissions using chrome.system.display.getInfo:

const info = await chrome.system.display.getInfo()
console.log(info.dpiX, info.dpiY)

It returns a DisplayUnitInfo object that tells you everything you might need to know.

Addendum to answers above for plain JS DOM

Also, it's worth noting that you can get an approximate pixel density combining pieces of information provided above. However, it's unlikely this will be useful for anything but logging purposes, IMO. I say this because any pixel values you use in your DOM/JS code aren't going to be "device pixel values". They'll likely have a multiplier applied.

The trick is to alter @nikksan's answer above and multiply by window.devicePixelRatio

Note that it is going to be the same answer every single time on each device, so it's probably only worth doing once.

function calcScreenDPI() {
    // Create a "1 inch" element to measure
    const el = document.createElement('div');
    el.style.width = '1in';

    // It has to be appended to measure it
    document.body.appendChild(el);

    // Get it's (DOM-relative) pixel width, multiplied by
    // the device pixel ratio
    const dpi = el.offsetWidth * devicePixelRatio;

    // remove the measurement element
    el.remove();
    return dpi;
}
Film answered 14/10, 2022 at 18:46 Comment(0)
D
0

You can create an element of 1in of fixed height, then look at its height in pixels

createDpiTestElements()
var dpi = getDpi()

Because

[dpi] = [px/in]

So let

  • p be an object's length in pixels [px]
  • i be that object's length in inches [in]
  • and d be the searched DPI/PPI for that object, in pixels per inches [dpi]

We get

d = p/i

So if we choose

i = 1

we get

d = p

JS Code

/**
 * @function
 * @inner
 */
function createDpiTestElements () {
  var getDpiHtmlStyle = 'data-dpi-test { height: 1in; left: -100%; position: absolute; top: -100%; width: 1in; }'

  var head = document.getElementsByTagName('head')[0]
  var getDPIElement = document.createElement('style')
  getDPIElement.setAttribute('type', 'text/css')
  getDPIElement.setAttribute('rel', 'stylesheet')
  getDPIElement.innerHTML = getDpiHtmlStyle
  head.appendChild(getDPIElement)

  var body = document.getElementsByTagName('body')[0]
  var dpiTestElement = document.createElement('data-dpi-test')
  dpiTestElement.setAttribute('id', 'dpi-test')
  body.appendChild(dpiTestElement)
}

/**
 * Evaluate the DPI of the device's screen (pixels per inche).
 * It creates and inpect a dedicated and hidden `data-dpi-test` DOM element to
 * deduct the screen DPI.
 * @method
 * @static
 * @returns {number} - The current screen DPI, so in pixels per inch.
 */
function getDpi () {
  return document.getElementById('dpi-test').offsetHeight
}
Declassify answered 24/9, 2016 at 17:59 Comment(1)
At least for me this doesn't work at all. On my screen 1 CSS inch === 0.9382677165 real inches since my screen has a pixel pitch of 0.24825 mm === 102.3162135 ppi and not 96 ppi which this reports, even my phone with 326 ppi reports 96 ppi. Of course if your screen is 96 ppi you're probably going to get just that by coincidence. I'm not sure if what you're trying to achieve is even possible. In CSS, 1 inch seems to more often than not be exactly 96 pixels.Alternately
S
-2

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

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

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

Stacte answered 18/6, 2015 at 22:18 Comment(1)
I not sure to understand... offsetWidth only give the width of the element?Inexact

© 2022 - 2024 — McMap. All rights reserved.