从 JS/CSS 检测系统 DPI/PPI?

IT技术 javascript css mobile dpi ppi
2021-02-05 17:43:22

我正在开发一种独特的应用程序,它需要根据显示图像的设备以特定分辨率生成图像。因此,在常规 Windows 浏览器 (96ppi)、iPhone (163ppi)、Android G1 (180ppi) 和其他设备上的输出是不同的。我想知道是否有办法自动检测到这一点。

我最初的研究似乎拒绝了。我看到的唯一建议是在 CSS 中创建一个宽度指定为“1in”的元素,然后检查其 offsetWidth(另请参阅如何通过 javascript 访问屏幕显示的 DPI 设置?)。有道理,但 iPhone 用这种技术对我撒谎,说它是 96ppi。

另一种方法可能是以英寸为单位获取显示器的尺寸,然后除以以像素为单位的宽度,但我也不知道该怎么做。

6个回答

<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>

从这里抓取http://www.infobyip.com/detectmonitordpi.php适用于移动设备!(安卓 4.2.2 测试)

实际上,它在 Firefox 中不起作用。Firefox 本身在 4k 显示器上看起来很奇怪。在 chrome 中,即它分叉非常好。
2021-03-31 17:43:22
我不明白你为什么这么认为。
2021-04-05 17:43:22
您所做的就是将常数 96 乘以 devicePixelRatio(可以覆盖)。这不是获得准确 ppi 的一致方法。
2021-04-06 17:43:22
因为我输入的单词是有意义的?在所有设备上,css 中的 1in 被定义为 96px,因此在 px 中测量一个宽度为 1in 的 div 将始终给出 96。然后你只是将它(同样,将始终为 96)乘以 devicePixelRatio 而不是根据标准或限制,它可以是任何东西,特别是任何人都可以用他们想要的任何值覆盖它。总之,这种方法是不可靠的。
2021-04-10 17:43:22

我想出了一种完全不需要 DOM 的方法……

DOM 可能很混乱,需要您在不知道width: x !important样式表中发生了什么的情况下将内容附加到正文中。您还必须等待 DOM 准备好使用...

/**
 * 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)

这始终返回 96,即使在移动设备上也是如此。这成为没有意识到英寸被定义为 96px 的经典错误的受害者。
2021-03-19 17:43:22
结果应该是准确的吗?我的监视器文档显示为 93,而您的函数显示为 96。
2021-03-27 17:43:22
数字应该是准确的。它通过在函数返回 false 之前执行 n^2 来进行假设,然后通过取中间数字来更接近该数字。你可以在这里尝试:fiddle如果函数说它是 93,那么它应该是 93。认为浏览器有一些根本性的问题,浏览器不知道屏幕分辨率是多少,所以它只是假设它是 96
2021-03-29 17:43:22
这段代码确实工作得很好,但根本不可读
2021-04-01 17:43:22
这是一个更好的版本:repl.it/@duzun/findDPIjs#script.js
2021-04-03 17:43:22

resolutionCSS 媒体查询——它允许您将 CSS 样式限制为特定分辨率:

但是,它仅受 Firefox 3.5 及更高版本、Opera 9 及更高版本和 IE 9 支持其他浏览器根本不会应用您的分辨率特定样式(尽管我没有检查非桌面浏览器)。

哇,我只能想象创建一个样式表,以 1 或 0.1dpi 范围增量列出所有可能的分辨率,并根据应用的样式推断最接近的实际屏幕分辨率......
2021-03-23 17:43:22
2021-04-05 17:43:22
这似乎根本不准确...... Endless 的答案似乎对这个查询进行了二分搜索,但在我的设备上,@Rémi 链接的操场给出了相同的无效结果......
2021-04-07 17:43:22

这是对我有用的方法(但没有在手机上测试过):

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

然后我放入.js: screenPPI = document.getElementById('ppitest').offsetWidth;

这让我得到了 96,这对应于我系统的 ppi。

这不适用于所有设备。我的 Android 手机也报告 96dpi。
2021-03-13 17:43:22
CSS 规范将 1 px 定义为 1/96 英寸,这就是为什么您的计算将始终返回 96。该英寸不是屏幕上的一英寸,而是考虑到您眼睛的距离,这意味着它在不同的设备。浏览器供应商需要将该因素设置为有意义的值,但情况并非总是如此。
2021-03-13 17:43:22
它应该有效,但不幸的是所有浏览器都认为 1in = 96px 和 1cm == 37.8px。漏洞?
2021-03-31 17:43:22
这似乎不适用于任何设备。一切似乎都报告 96ppi:codepen.io/anon/full/mrfvg
2021-04-11 17:43:22
不是错误 - “px”不是屏幕像素,它是 0.75 pt 的固定长度,它本身是 1/72 英寸。
2021-04-11 17:43:22

@Endless 的回复很好,但根本不可读,这是一个类似的方法,具有固定的最小值/最大值(应该是好的)

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

matchMedia 现在得到了很好的支持,应该会产生很好的结果,请参阅http://caniuse.com/#feat=matchmedia

小心浏览器不会给你准确的屏幕 dpi,而只是一个近似值

这绝对更具可读性。但是我的和你的不同的是,我只执行了 11 次 matchMedia 以找出它是 96,而你的代码尝试了 56 到 2000 之间的每个可能的数字
2021-03-12 17:43:22
这在 WebKit/Safari (iOS 11) 上不起作用,似乎那里尚不支持最大分辨率
2021-03-18 17:43:22