如何从JS中的图像获取DPI?

Oly*_*ius 2 html javascript html5-canvas

我在 HTML5 画布上工作来计算两点之间的图像距离。我想将此距离(以像素为单位)转换为厘米。我找到了一个公式:像素 * 2.54 / DPI。那么,我想知道是否可以在 JS 中获取 DPI 图像属性?或者,我可以使用最简单的方法从像素计算厘米吗?

谢谢你。

Kai*_*ido 5

您所要求的是,要检索任何数字的物理显示尺寸(以厘米为单位),没有大量启发式方法就无法完成,也就是说,我们作为网络开发人员无法为所有访问者做到这一点。


关于你的公式:

DPI -每英寸点数

这是衡量一英寸中可以容纳多少点的指标。该装置通常用于打印机或扫描仪。然而,显示器没有点,因此DPI对它没有意义。

像图像这样的数字媒体可能会在其元数据中嵌入DPI信息,但这只是对扫描仪在生成文件时使用的设置的提示,或者是作者对应该打印的预期尺寸的提示。只有少数专用软件会使用这些信息,您的网络浏览器不属于其中。

数字像素 - (光栅图片单元)。

这是光栅图形中可见信息的最小单位。这些信息可能以多种方式存储,但除了创建新的虚假数据外,无法通过其他方式进行分割。这通常是我们在1920x1080px 中所指的“ px ” 。 为了更容易理解,我们可以以位图为例,其中每个数字像素由文件中自己的一组位表示,为了更容易理解,让我们以 8 位位图图像(单色)为例,一般是灰度)。这里 8 位用于表示单个数字像素(一个色点)。例如,我们可以使用以下信息制作 2x2px 位图:

[2, 125, 255, 125, 255]
 |   |    |    |    - pixel (2,2) 100% intensity
 |   |    |     - pixel (2,1) 50% intensity
 |   |     - pixel (1,2) 100% intensity
 |    - pixel (1,1) 50% intensity
  - width (nb of digital pixels per line)
/* height can be determined by the `length of data array / width` */
Run Code Online (Sandbox Code Playgroud)

但请注意,所有光栅图像都不是位图,它们并不都具有这种位像素关系,但它们都具有数字像素的概念,因为它们确实保存了最小的颜色信息块。


澄清这两个概念后,我们可以解释您的公式的含义:

const pxTocm = (pixels, DPI) => pixels * 2.54 / DPI;
Run Code Online (Sandbox Code Playgroud)

如果我们采用 150*150px 的光栅图像,并使用分辨率为 300DPI 的相当好的喷墨打印机打印它,这个公式将正确地给我们 1.27 厘米或 0.5 英寸

但这只有在我们知道打印分辨率时才有效


好吧,那我们就用屏幕分辨率吧。

PPI - 每英寸像素数。

这是我们大多数显示器所需要的。与 DPI 非常相似,它测量显示器在单英寸中包含的物理像素数。显示器
物理像素因使用的显示器类型而异,但例如在大多数 LCD 显示器中,一个物理像素由三个二极管组成,一个红色、一个绿色和一个蓝色,也称为子像素。

笔记本电脑 LCD 屏幕上的 sub-PIXEL 显示元素的照片
您可以看到组成单个像素的所有三个子像素组件。
图片来源: wikimedia.org 的 CC-BY-SA 4.0 Krapteek88

所以我们确实可以将你的公式改写为

const pxTocm(pixels, PPI) => pixels * 2.54 / PPI;
Run Code Online (Sandbox Code Playgroud)

但这只有在图像以 100% 显示时才有效,即一个数字像素占用一个物理像素,这在网络上很少见,而且我们需要知道这个 PPI 值

从 Web API 中,我们无法知道PPI值。我们甚至不能确定我们是在显示器上显示,它很可能是一台光束投影仪,对此PPI的概念没有任何意义。

我们拥有的最接近的是屏幕分辨率(在Window.screen对象下,但这只会为我们提供显示器拥有的数字像素数;我们仍然错过了该显示器的实际物理尺寸。

PPI = Math.hypot(screen.width, screen.height) / physical_size_of_diagonal
// and we don't have any way to find this diagonal...
Run Code Online (Sandbox Code Playgroud)

但是,window.devicePixelRatio如果不是我的屏幕的PPI,我听到了什么?

为了解释这一点,我们首先需要解释什么是CSSpx

CSS px- 读作“像素”但不是像素。

Apx是一个单位,被 W3C 称为 “CSS 的魔法单位”。它的价值取决于支撑,以及它与观察者眼睛的距离(!)。在这里,您可以找到关于什么是CSS参考像素的通俗易懂的解释。基本上,如果您在有害距离处在显示器上观看,如果您在更近的距离上观看手机,它的大小应该相同。

我希望你明白将它映射到现实生活中的测量是多么困难。

window.devicePixelRatio

此值表示将用于显示CSS px.
可能很有用,因为有了这个值,我们可以精确地将一个 css 映射px到正在使用的物理像素的数量。

如果我们知道 CSSpx真正代表什么(我们是在显示器上、移动设备上还是其他设备上?),以及用户显示器当前的 PPI 分辨率是多少(但我们不知道),那么我们就可以测量显示器上显示的尺寸。(但我们不能)。

所以是的,我们可以在 96PPI 桌面显示器上,在没有操作系统缩放的情况下,得到他们回答中提供的类型或公式@JuMoGar(注意,尽管他们弄错了):

const CSSpxTocm = (CSSpx) => CSSpx * 2.54 / (96 / devicePixelRatio);
Run Code Online (Sandbox Code Playgroud)

96CSSpx单元在 96 英寸处使用的 96PPI 硬编码值在哪里。

但只要在手机上试一试,你就会发现它有多坏。如果从移动设备上更容易,那就是小提琴。

[2, 125, 255, 125, 255]
 |   |    |    |    - pixel (2,2) 100% intensity
 |   |    |     - pixel (2,1) 50% intensity
 |   |     - pixel (1,2) 100% intensity
 |    - pixel (1,1) 50% intensity
  - width (nb of digital pixels per line)
/* height can be determined by the `length of data array / width` */
Run Code Online (Sandbox Code Playgroud)
const pxTocm = (pixels, DPI) => pixels * 2.54 / DPI;
Run Code Online (Sandbox Code Playgroud)
const pxTocm(pixels, PPI) => pixels * 2.54 / PPI;
Run Code Online (Sandbox Code Playgroud)

在我的 125PPI 笔记本电脑的显示器(13.3in 1280x1080px) 上,它已经是错误的,说它是 2.54cm,而实际上它大约是 2.2cm,但是在我的 Galaxy S6 手机上,它返回 10.16cm而 IRL,它大约是 1.7厘米。

为什么?因为屏幕有 ~577 PPI,但仍然每个CSS只使用一个物理像素。这意味着仍然是,但PPI与预期的 96 相差甚远,此公式返回荒谬。(S6 屏幕的对角线为 5.1in, ~12.9cm)pxdevicePixelRatio1


JuM*_*Gar 3

您可以使用 JavaScript 从图像中获取 cms 的大小。请注意,每个设备的 DPI 都不同,因此我用来window.devicePixelRatio获取显示图像的屏幕的 DPI(可以是笔记本、手机、平板电脑等)。

一种方法是:

/* Convert px to cm */
function getSizeInCM(sizeInPX) {
   return sizeInPX * 2.54 / (96 * window.devicePixelRatio)
};

/* get width and height of an image in cms */
var img = document.getElementById('IMAGE_ID'),
var width = getSizeInCM(img.clientWidth),
var height = getSizeInCM(img.clientHeight);
Run Code Online (Sandbox Code Playgroud)

如果只想获取一张图像的像素,则更简单:

var imageWidth = document.getElementById("IMAGE_ID").width;
var imageHeigth = document.getElementById("IMAGE_ID").height;

// or...

var imageWidth = document.getElementById("IMAGE_ID").clientWidth;
var imageHeigth = document.getElementById("IMAGE_ID").clientHeight;
Run Code Online (Sandbox Code Playgroud)

另一种方法是:您将需要一个额外的库:Blueimp 的加载图像库并使用其EXIF parsing extension

这是返回其坐标分辨率的代码:

loadImage.parseMetaData(FILE, function(meta) {
    if (!meta.exif) { return; }

    var resX = meta.exif.get('XResolution');
    var resY = meta.exif.get('YResolution');
});
Run Code Online (Sandbox Code Playgroud)