【问题标题】:How can I get DPI from image in JS?如何从 JS 中的图像中获取 DPI?
【发布时间】:2019-01-29 22:53:31
【问题描述】:

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

谢谢。

【问题讨论】:

  • DPI(每英寸点数)是供打印机使用的信息。您不能将其用于数字媒体。那里没有公制距离的概念。例如,有人在手机上显示您的图像,而其他人则使用光束投影仪。
  • DPI 与屏幕相关,既然存在高密度屏幕,我认为这就是他们要问的(更准确地说,它称为 PPI 或像素密度但 DPI 足够接近)
  • @DanielBeck 不,它仍然无关紧要,高密度与否,您在 EXIF 元数据中的 DPI 信息在显示器上显示时会被忽略。您混淆了光栅图像中的像素数,以及监视器用于显示px(CSS 单元)的物理像素数,称为 DPR。这些是不相关的,你无法得到 OP 愿意得到的(物理显示的尺寸)。请注意,由于至少生产了两台显示器,因此存在 PPI 差异。
  • @Kaiido 他们使用了错误的术语,同意。但他们不是询问 EXIF 数据,而是询问canvas 上像素之间的物理距离。哪个可以从 DPR 中确定。
  • @DanielBeck ...我正在使用极端的例子来说明它无法做到。现在,您必须了解,即使在非极端情况下,它仍然无法完成。您可能很幸运,遇到了一个使用 96PPI 显示器( 最常见于桌面显示器)的用户,该用户在浏览器级别和操作系统级别都没有缩放(这意味着如果在 Windows 上他们确实更改了默认设置),那么是的,您可能会找到它。但再一次,这只是运气,而且几乎有同样多的机会弄错了。

标签: javascript html html5-canvas


【解决方案1】:

您所要求的,要检索任何数字的物理显示尺寸 cm,如果没有很多启发式方法,就无法完成,也就是说,我们作为网络开发人员没有办法为我们所有的访问者做这件事。


关于你的公式:

DPI - Dots Per Inch.

这是衡量一英寸内可以容纳多少个点的指标。该单元通常用于打印机或扫描仪。然而,监视器没有点,因此 DPI 对它没有意义。

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

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

这是raster graphic 中可见信息的最小单位。这些信息可能以多种方式存储,但不能通过创建新的虚假数据以外的其他方式进行分割。这通常是我们在 1920x1080px 中所指的“px”。
为了更容易理解,我们可以使用位图的情况,其中每个数字像素在文件中由它自己的一组位表示,为了更容易理解,让我们举个例子8bit位图图像(单色,一般为灰度)。这里 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` */

但请注意,所有光栅图像都不是位图,它们也不都有这种 bits-pixel 关系,但它们都有数字像素的概念,就像在最小的块中一样他们确实拥有颜色信息。


明确了这两个概念,我们就可以解释一下你的公式是什么意思了:

const pxTocm = (pixels, DPI) => pixels * 2.54 / DPI;

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

但这只有在我们知道打印分辨率的情况下才有效


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

PPI - 每英寸像素数。

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


您可以看到组成单个像素的所有三个子像素组件。
图片来源:CC-BY-SA 4.0 Kapteek88 for wikimedia.org

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

const pxTocm(pixels, PPI) => pixels * 2.54 / PPI;

但这只有在图像以 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...

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

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

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

px 是一个单位,called by W3C “CSS 的魔法单位”。它的值取决于支撑,以及它到观众眼睛的距离(!)。 Here 您可以找到关于 CSS 的参考像素 的非常容易理解的解释。 基本上,如果您在距离较远的地方在显示器上观看,或者在较近的距离在手机上观看,它的大小应该是相同的。

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

window.devicePixelRatio

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

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

所以,是的,我们可以在没有 OS 缩放的 96PPI 桌面显示器上,获得@JuMoGar 在他们的答案中提供的种类或公式(请注意,尽管他们弄错了):

const CSSpxTocm = (CSSpx) => CSSpx * 2.54 / (96 / devicePixelRatio);

其中96 是 CSS px 单位使用的 96PPI 硬编码值,以 96 英寸为单位。

但只要在手机上试一试,你就会发现它有多坏。 As a fiddle if it's easier from mobile.

const CSSpxTocm = (CSSpx) => CSSpx * 2.54 / (96 / devicePixelRatio);

console.log(CSSpxTocm(96) + 'cm');
.test {
  border-top: 3px solid blue;
  height: 10px;
  width: 96px;
}
<div class="test px"></div>

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

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

【讨论】:

    【解决方案2】:

    您可以使用 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);
    

    如果你只想获取一张图片的像素,那就更简单了:

    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;
    

    另一种方法:你需要一个额外的库:Blueimp's Load Image library 并使用它的EXIF parsing extension

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

    loadImage.parseMetaData(FILE, function(meta) {
        if (!meta.exif) { return; }
    
        var resX = meta.exif.get('XResolution');
        var resY = meta.exif.get('YResolution');
    });
    

    【讨论】:

    • 我不会重复这是多么不可靠,已经在 cmets 中就这个问题做过了,但我会注意它应该是 96/DPR,而不是 *。
    【解决方案3】:

    Sharp JavaScript 库可以很好地使用withMetadata 函数获取和设置图像文件的分辨率/密度。

    简单示例:

    // get the metadata of an image 
    sharp('input.jpg')
      .withMetadata()
      .toFile('output-with-metadata.jpg')
      .then(info => { ... });
    
    // Set output metadata to 96 DPI
    const data = await sharp(input)
      .withMetadata({ density: 96 })
      .toBuffer();
    

    Npm 模块:sharp

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-18
      • 1970-01-01
      • 2018-09-17
      • 1970-01-01
      相关资源
      最近更新 更多