简体   繁体   English

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

[英]How can I get DPI from image in JS?

I work on a HTML5 canvas to calculate distance on image between two points.我在 HTML5 canvas 上工作来计算两点之间的图像距离。 I want to convert this distance in pixel to cm.我想将这个以像素为单位的距离转换为厘米。 I found a formula: pixels * 2.54 / DPI.我找到了一个公式:像素 * 2.54 / DPI。 So, I would like to know if it's possible to get DPI image properties in JS?所以,我想知道是否可以在 JS 中获取 DPI 图像属性? Or, can I use an easiest way to calculate cm from pixels?或者,我可以使用最简单的方法从像素计算厘米吗?

Thank you.谢谢你。

You can get the size of cms from an image using JavaScript. 您可以使用JavaScript从图像中获取cms的大小。 Take in care that DPI are different in each device so, I use window.devicePixelRatio to get DPI of the screen that shows the image (can be a NoteBook, Mobile, Tablet,...). 请注意,每个设备中的DPI都不相同,因此,我使用window.devicePixelRatio来获取显示图像的屏幕的DPI(可以是笔记本,移动设备,平板电脑等)。

One way is: 一种方法是:

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

If you only want get the pixels of one image, it is simpler: 如果只想获取一张图像的像素,则比较简单:

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;

Another way to do that: You will need an extra library: Blueimp's Load Image library and use its EXIF parsing extension 执行此操作的另一种方法:您将需要一个额外的库: Blueimp的Load Image库并使用其EXIF parsing extension

Here is a code which returns its coordinates resolution: 这是返回其坐标分辨率的代码:

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

    var resX = meta.exif.get('XResolution');
    var resY = meta.exif.get('YResolution');
});

What you are asking for, to retrieve the physical displayed size in cm of anything digital, can't be done without a lot of heuristics, that is, we as web-developer have no way to do it for all our visitors. 您需要的是,要获取以厘米为单位的任何数字形式的物理显示大小,没有很多启发法就无法完成,也就是说, 作为Web开发人员我们无法为所有访问者做到这一点。


About Your formula: 关于您的公式:

DPI - Dots Per Inch . DPI-每英寸点数

This is a measure of how many dots can fit in a single inch. 这是一英寸可以容纳多少个点的度量。 This unit is usually for printers or scanners. 本机通常用于打印机或扫描仪。 A monitor however has no dots and thus DPI has no meaning for it. 但是,监视器没有点,因此DPI没有意义。

Digital media like images may embed a DPI information in their metadata, but this is only a hint on either the settings the scanner used when generating the file, either a hint by the author for the intended size it should be printed . 诸如图像之类的数字媒体可能会在其元数据中嵌入DPI信息,但这仅是有关扫描程序在生成文件时使用的设置的提示,或者是作者针对应打印的预期大小的提示。 Only a few dedicated softwares will make use of this information, and your web browser is not of them. 仅少数专用软件将使用此信息,而您的Web浏览器不属于这些软件。

Digital Pixel - (raster Picture-Cell). 数字像素-(光栅图像单元)。

This is the smallest unit of visible information in a raster graphic . 这是栅格图形中可见信息的最小单位。 These information may be stored in many ways, but is not divisible by other means than creating new, fake data. 这些信息可能以多种方式存储,但是除了创建新的伪造数据外,其他方法无法将其整除。 That's generally the " px " we refer to in 1920x1080px . 通常,这就是我们在1920x1080px中指的“ px ”。
To make it easier to understand, we can take the case of bitmaps, where each digital pixel is represented by its own set of bits in the file, to make it easier again, let's take the example of an 8bit bitmap image (single-color, generally gray-scale). 为了更容易理解,我们以位图为例,其中每个数字像素都由文件中自己的位集表示,为了使其更加容易,让我们以一个8位位图图像(单色)为例。 ,通常是灰度)。 Here 8 bits are used to represent a single digital pixel (a color dot). 此处8位用于表示单个数字像素(色点)。 For instance we can make a 2x2px bitmap with these information: 例如,我们可以使用以下信息制作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` */

Beware though, all raster images are not bitmaps, and they don't all have this bits-pixel relation, but they do all have a concept of digital pixel, as in the smallest block of color information they do hold. 但是请注意,所有光栅图像都不是位图,它们也不都具有位像素关系,但是它们都具有数字像素的概念,因为它们确实保留了最小的颜色信息块。


With these two concepts clarified, we can explain what your formula means: 澄清了这两个概念之后,我们可以解释您的公式的含义:

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

If we take a 150*150px raster image, and print it using a quite good inkjet-printer with a 300DPI resolution, this formula will correctly give us 1.27cm, or 0.5in 如果我们拍摄一个150 * 150px的光栅图像,并使用具有300DPI分辨率的性能很好的喷墨打印机进行打印,则此公式将正确地为我们提供1.27cm或0.5in

But this only works if we know the printed resolution . 但这仅在我们知道打印分辨率的情况下才有效


Alright, then let's just use the screen resolution. 好吧,那我们就使用屏幕分辨率吧。

PPI - Pixels Per Inch. PPI-每英寸像素

This is what we would need for most monitors. 这是大多数显示器所需的。 Very similar to DPI, this measures the number of physical pixels a monitor does contain in a single inch. 与DPI非常相似,它测量监视器在一英寸中确实包含的物理像素数。
What a physical pixel for a monitor is vary with the type of monitor used, but for instance in most LCD monitors, one physical pixel is made of three diodes, one Red, one Green, and one Blue, also called sub-PIXELs. 监视器的物理像素随所用监视器的类型而变化,但是例如在大多数LCD监视器中,一个物理像素由三个二极管组成,一个红色,一个绿色和一个蓝色,也称为子像素。

笔记本电脑的LCD屏幕上的子PIXEL显示元素的照片
You can see all three sub-Pixels components composing a single pixel. 您可以看到组成单个像素的所有三个子像素组件。
Image credits: CC-BY-SA 4.0 Krapteek88 for wikimedia.org 图片来源:Wikimedia.org的CC-BY-SA 4.0 Krapteek88

So we could indeed rewrite your formula to be 因此,我们确实可以将您的公式重写为

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

But that would work only if the image was displayed at 100%, that is one digital pixel takes up one physical pixel , which is rarely the case on the web, and moreover, we would need to know this PPI value . 但这仅在图像以100%显示时才有效,即一个数字像素占用一个物理像素 ,这在网络上很少见,此外, 我们需要知道此PPI值

From the Web APIs, we have no way of knowing that PPI value. 从Web API,我们无法知道该PPI值。 We can't even be sure we are displaying to a monitor, it could very well be a beam projector, for which the concept of PPI has no meaning whatsoever. 我们甚至无法确定要显示在监视器上,它很可能是光束投影仪,对于PPI的概念毫无意义。

The closest we have is the screen resolution (under Window.screen object, but this will only give us the number of digital pixels the display holds; we still miss the actual physical size of this display. 我们所拥有的最接近的是屏幕分辨率(在Window.screen对象下,但是这只会给我们显示器所拥有的数字像素数量;我们仍然会错过该显示器的实际物理尺寸。

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

But what is window.devicePixelRatio I heard about if not my screen's PPI ? 但是,如果不是屏幕的PPI,我听说的window.devicePixelRatio是什么?

To explain that, we first need to explain what is a CSS px 为了解释这一点,我们首先需要解释什么是CSS px

CSS px - Reads as "pixel" but is not a pixel. CSS px读取为“像素”,但不是像素。

A px is an unit, called by W3C "the magic unit of CSS" . px是一个单位, 被W3C称为 “ CSS的魔术单位” It value depends on the support, and its distance to the viewer's eyes (!). 它的值取决于支撑物及其与观察者眼睛的距离(!)。 Here you can find a quite accessible explanation of what is a reference pixel for CSS. 在这里,您可以找到关于CSS的参考像素的易于理解的解释。 Basically, it should look the same size if you are viewing on a monitor at harm distances, and if you are looking on a phone at closer distance. 基本上,如果您在显示器上以伤害距离观看,并且在手机上以更近的距离观看,则其尺寸应相同。

I hope you get how hard it is to map this to a real-life measurement. 希望您能将其映射到实际测量中有多困难。

window.devicePixelRatio

This value represents the number of physical pixels that will get used to display a CSS px . 此值表示将用于显示CSS px的物理像素数。
This could have been useful, because with this value we can map precisely one css px to the number of physical pixels being used. 可能很有用,因为有了这个值,我们可以精确地将一个css px映射到所使用的物理像素数。

If we knew what a CSS px really represents ie (are we on a monitor or a mobile device or some other device?), and what is the current PPI resolution of our user's monitor (but we don't), then we could have measured the displayed size on the monitor. 如果我们知道CSS px真正代表什么(即(我们是在显示器,移动设备还是其他设备上?),以及用户显示器的当前PPI分辨率是多少(但我们没有),那么我们可以测量了显示器上显示的尺寸。 (But we can't). (但是我们不能)。

So yes, we can, on a 96PPI desktop monitor, with no OS zoom, get the kind or formula @JuMoGar provided in their answer (note though they got it wrong): 因此,是的,我们可以在没有OS缩放的96PPI台式机显示器上,获得其答案中提供的种类或公式@JuMoGar(请注意,尽管他们弄错了):

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

where 96 is the 96PPI hard-coded value CSS px unit uses in their 96th of an inch. 其中96是CSS px单位在96英寸处使用的96PPI硬编码值。

But simply try it on mobile phone, and you'll see how broken it is. 但是只需在手机上尝试一下,您就会发现它有多坏。 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> 

On my 125PPI laptop's monitor (13.3in 1280x1080px) , it is already wrong, stating that it is 2.54cm, while it is in fact around 2.2cm, but on my Galaxy S6 phone, it returns 10.16cm while IRL, it is roughly 1.7cm. 在我的125PPI笔记本电脑的显示器(1280x1080px中为13.3)上 ,这已经是错误的,指出它是2.54cm,而实际上大约是2.2cm,但是在我的Galaxy S6手机上, 它返回10.16cm,而IRL大约是1.7厘米。

Why? 为什么? Because the screen has ~577 PPI, but still, it uses only one physical pixel per CSS px . 由于屏幕具有〜577 PPI,但每个CSS px仅使用一个物理像素 This means the devicePixelRatio is still 1 , but the PPI being so far from expected 96, this formula returns absurdities. 这意味着devicePixelRatio仍为1 ,但PPI距离预期值96太远,此公式返回荒谬性。 (The diagonal of an S6 screen is 5.1in, ~12.9cm) (S6屏幕的对角线为5.1英寸,约12.9厘米)

Sharp JavaScript library works well to get and set the resolution/density for the image files with withMetadata function. Sharp JavaScript 库可以很好地使用withMetadata函数获取和设置图像文件的分辨率/密度。

Simple example:简单的例子:

// 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 module: sharp npm 模块: sharp

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM