Обнаружение системы DPI/PPI из JS/CSS?

Я работаю над уникальным приложением, которое должно генерировать изображения при определенных разрешениях в соответствии с устройством, на котором они отображаются. Таким образом, результат отличается от обычного браузера Windows (96ppi), iPhone (163ppi), Android G1 (180ppi) и других устройств. Мне интересно, есть ли способ обнаружить это автоматически.

Мои первоначальные исследования, похоже, говорят "нет". Единственное предложение, которое я видел, - это создать элемент, ширина которого указана как "1in" в CSS, а затем проверить его offsetWidth (см. Также Как получить доступ к экрану. Настройки DPI через javascript?). Имеет смысл, но iPhone лжет мне с этой техникой, говоря это 96ppi.

Другим подходом может быть измерение размеров дисплея в дюймах, а затем разделение на ширину в пикселях, но я не уверен, как это сделать.

Ответ 1

Существует медиа-запрос resolution CSS - он позволяет вам ограничить стили CSS конкретными разрешениями:

Однако поддерживается только Firefox 3.5 и выше, Opera 9 и выше, и IE 9. Другие браузеры вообще не будут применять ваши специфичные для разрешения стили (хотя я не проверял браузеры без рабочего стола).

Ответ 2

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

Ответ 3

Я придумал способ, который не требует DOM... вообще

DOM может быть беспорядочным, требуя, чтобы вы добавляли материал в тело, не зная, что происходит с width: x !important в вашей таблице стилей. Вам также придется подождать, когда DOM будет готов к использованию...

// Binary search, (faster then loop)
// also don't test every possible value, since it tries low, mid, and high
// http://www.geeksforgeeks.org/find-the-point-where-a-function-becomes-negative/
function findFirstPositive(b, a, i, c) {
  c=(d,e)=>e>=d?(a=d+(e-d)/2,0<b(a)&&(a==d||0>=b(a-1))?a:0>=b(a)?c(a+1,e):c(d,a-1)):-1
  for (i = 1; 0 >= b(i);) i *= 2
  return c(i / 2, i)|0
}


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

console.log(dpi)

Ответ 4

Вот что работает для меня (но не тестировало его на мобильных телефонах):

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

Затем я ввел .js: screenPPI = document.getElementById('ppitest').offsetWidth;

Это получило меня 96, что соответствует моей системе ppi.

Ответ 5

Мне также нужно было отображать одно и то же изображение с одинаковым размером на разных экранах, но только для Windows IE. Я использовал:

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

В этом случае исходная ширина/высота изображения составляет 270 и 438, и изображение было разработано на экране 192dpi. screen.deviceXDPI не определен в Chrome, и функция масштабирования должна быть обновлена ​​для поддержки браузеров, отличных от IE

Ответ 6

function getPPI(){
  // create an empty element
  var div = document.createElement("div");
  // give it an absolute size of one inch
  div.style.width="1in";
  // append it to the body
  var body = document.getElementsByTagName("body")[0];
  body.appendChild(div);
  // read the computed width
 var ppi = document.defaultView.getComputedStyle(div, null).getPropertyValue('width');
 // remove it again
 body.removeChild(div);
 // and return the value
 return parseFloat(ppi);

}

(Из VodaFone)

Ответ 7

Ответ от @Endless довольно хороший, но не читаемый вообще, это аналогичный подход с фиксированным min/max (он должен быть хорошим)

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

Будьте осторожны, браузер не даст вам точный экран, но только приближение

Ответ 8

Я думаю, что ваш лучший подход - объединить предложение "снифферного" изображения с матрицей известных DPI для устройств (через пользовательский агент и другие методы). Это будет неточно и будет больно поддерживать, но, не зная больше о приложении, вы пытаетесь сделать это наилучшим предложением, которое я могу предложить.

Ответ 9

DPI по определению привязан к физическому размеру дисплея. Таким образом, вы не сможете иметь реальный DPI, не зная точно аппаратное обеспечение.

Современные ОС согласовали общую ценность, чтобы иметь совместимые дисплеи: 96 точек на дюйм. Это позор, но это факт.

Вам придется полагаться на обнюхивание, чтобы угадать реальный размер экрана, необходимый для вычисления разрешения (DPI = PixelSize/ScreenSize).

Ответ 10

Я только что нашел эту ссылку: http://dpi.lv/. В основном это webtool для обнаружения разрешения клиентского устройства, dpi и размера экрана.

Я посетил на своем компьютере и мобильном телефоне, и он обеспечивает правильное разрешение и DPI для меня. Для него существует репозиторий github, поэтому вы можете видеть, как он работает.

Ответ 11

Разве ты не можешь сделать что-нибудь еще? Например, если вы генерируете изображение, которое должно распознаваться камерой (т.е. Вы запускаете свою программу, проведите по мобильному телефону по камере, происходит волшебство), вы не можете использовать что-то независимое от размера?

Если это приложение для развертывания в контролируемых средах, можете ли вы предоставить программу калибровки? (вы можете сделать что-то простое, например, визитные карточки с маленькой линейкой, использовать его во время процесса калибровки).

Ответ 12

Создайте список известных DPI: fooobar.com/info/270653/...

Обнаружение точного устройства. Используя что-то вроде:

navigator.userAgent.toLowerCase();

Например, при обнаружении мобильного:

window.isMobile=/iphone|ipod|ipad|android|blackberry|opera mini|opera mobi|skyfire|maemo|windows phone|palm|iemobile|symbian|symbianos|fennec/i.test(navigator.userAgent.toLowerCase());

И прибыль!