JavaScript/NodeJS和Electron中的图像DPI是什么?

3
我正在使用Electron构建一个主要针对Mac OS X的应用程序。用户可以将图像拖放到页面上,页面将创建一个源路径为拖放图像的<img>,用户可以看到该图像。 问题

如果用户在Retina显示器上截取屏幕截图,然后将图像拖放到页面上,图像将以两倍大小显示。我需要知道如何以其自然尺寸的一半显示此图像。

可能的解决方案

我相信如果我检查图像的DPI,就能可靠地判断图像是否为Retina。在Mac上的预览应用程序中,我可以看到图像的DPI为144。基本上,如果DPI为144或更高,则它是Retina,对吗?

是否有一种方式,可以使用Electron的Native Image或NodeJS来读取给定图像的数据?

注意:Mac OS X将截图保存为PNG格式,因此没有exif数据。

编辑和更新:我相信我可以从查看HEX信息中告诉图像的DPI。例如,fs.readFileSync('file.type').toString('hex'),然后对于PNG文件查找70 48 59 73,如此处所述,或者对于JPG文件查找FFD8FFE000104A464946000101,如此处所述。我现在遇到的问题是尝试使用Electron的NativeImage处理从剪贴板粘贴的图像时。

如果我从剪贴板粘贴PNG,并执行nativeImage.toPng().toString('hex'),则输出如下:

89504e470d0a1a0a0000000d49484452000001fc000001680806000000b2a54946000005c249444154789cedd5410dc03010c0b0ae448f3f8a0dc554a9b111e4976766de05005c6d9f0e0000fe67f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f80010f0014a0204ec5f3e63f20000000049454e44ae426082

在这个字符串中,我应该在哪里找到DPI信息?

编辑和更新2:我想知道这是否可能是Electron内部的一个错误。当我从预览中复制一个144 PPI的图像并将其粘贴到我的应用程序中,然后将其从我的应用程序中复制并粘贴到新的预览窗口中时,它会更改为72 PPI。Electron有可能去掉这些信息吗?

Preview DPI

应@robertklep的请求,这里是块的截图(抱歉,我覆盖了我的应用程序中的复制,所以现在无法复制文本)。

初始图像 Initial

复制/粘贴后 After copy


你能否包含一些示例图像以供测试吗? - Jon Surrell
任何在 Mac 上截取的屏幕截图都可以达到目的。 - atdrago
我们并不都坐在 Mac 电脑前 :) - Jon Surrell
这实际上影响了所有剪贴板,至少在 Mac 上是如此。这不是 Electron 或任何可以真正解决的问题。 - atdrago
2个回答

3
您展示的输出似乎是原始PNG数据(PNG签名为0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A)。
您可以解析数据中的不同块并查找pHYs块,这是(我认为)您需要从Mac OS X生成的PNG中提取分辨率信息的块。
一个简单的解析器可以处理所有的PNG块:
var image = nativeImage.toPng(); // or the result of fs.readFile*()

function* parseChunks(data) {
  var offset = 8; // skip PNG header

  while (offset < data.length) {
    var dataLength  = data.readUInt32BE(offset);
    var chunkLength = dataLength + 12;
    var typeStart   = offset + 4;
    var dataStart   = offset + 8;
    var dataEnd     = offset + 8 + dataLength;
    var crcEnd      = dataEnd + 4;

    yield {
      type : data.toString('ascii', typeStart, dataStart),
      data : data.slice(dataStart, dataEnd),
      crc  : data.slice(dataEnd, crcEnd),
    };

    offset = crcEnd;
  }
}

for (let chunk of parseChunks(image)) {
  // Extract pixel information
  if (chunk.type === 'pHYs') {
    var ppuX = chunk.data.readUInt32BE(0);
    var ppuY = chunk.data.readUInt32BE(4);
    var unit = chunk.data.readUInt8(8); // should always be `1`
    console.log('PPI', Math.round(ppuX * 0.0254));
  }
}

这在我的Mac上输出PPI 144,和预期的一样。

谢谢你的回答,但请看我的更新问题。从剪贴板读取图像时有方法获取此数据吗?似乎复制的图像不会包含这些数据。 - atdrago
@atdrago,你能否发布一份粘贴数据中块的列表?你可以重用我发布的代码,只需记录每个“chunk.type”。或者,如果可能的话,你能否将粘贴的图像写入文件并在某个地方发布,以便我可以查看? - robertklep
1
@atdrago 我相信Mac OS X剪贴板使用TIFF格式来存储图像数据,这意味着PNG会被转换为TIFF,一旦粘贴到Electron中,又会被转换回PNG。在任何一种转换过程中,元数据(如“pHYs”块)可能会丢失,导致您最终得到一个看起来大小加倍的图像。我认为没有办法避免这种情况 :-( - robertklep
很遗憾,我认为你是对的。这似乎与Electron无关。您可以通过截屏,在预览中打开,按Command + C,然后按Command + N轻松重现它。新图像将丢失其DPI数据。 - atdrago
据我所见,这仍然是一个相当高级的API:readImage()将返回一个NativeImage,它只支持PNG或JPEG格式,因此从“剪贴板格式”到PNG / JPEG的转换是自动处理的;似乎您无法访问原始数据。 - robertklep
显示剩余3条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接