Обнаружение системы 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());
И прибыль!