JavaScript/NodeJS和Electron?中的图像DPI

nhaq1z21  于 2023-01-30  发布在  Node.js
关注(0)|答案(2)|浏览(277)

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

    • 问题**

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

    • 可能的解决方案**

我相信,如果我检查图像的DPI,我应该能够可靠地判断图像是否是视网膜。在Mac上的Preview应用程序中,我可以看到图像的DPI是144。本质上,如果DPI是144或更高,那么它就是视网膜,对吗?
给定图像,是否有某种方法可以使用Electron的Native Image或NodeJS读取此数据?

    • 注意:**Mac OS X将屏幕截图作为PNG,因此没有exif数据。
      编辑和更新:我相信我可以从HEX信息中看出图像的DPI是多少。例如,fs.readFileSync('file.type').toString('hex'),那么对于PNG,查找70 48 59 73,如前面提到的here,或者对于JPG,查找FFD8FFE000104A464946000101,如前面提到的here。我现在遇到的问题是,当从剪贴板粘贴图像时,尝试使用Electron的NativeImage。

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

89504e470d0a1a0a0000000d49484452000001fc000001680806000000b2a54946000005c249444154789cedd5410dc03010c0b0ae448f3f8a0dc554a9b111e4976766de05005c6d9f0e0000fe67f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f80010f0014a0204ec5f3e63f20000000049454e44ae426082

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

***编辑和更新2:***我想知道这是否是Electron中的一个错误。当我从Preview中复制一张144 PPI的图像并将其粘贴到我的应用程序中,然后将其复制出我的应用程序并粘贴到一个新的Preview窗口中时,它会变为72 PPI。是否有可能Electron删除了这些信息?

大块

由@robertklep请求,这里是块的截图(对不起,我覆盖了我的应用程序中的复制,所以我现在不能真正复制文本)。

    • 初始映像**
    • 复制/粘贴后**
scyqe7ek

scyqe7ek1#

您显示的输出看起来是原始PNG数据(PNG签名是0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)。
您可以解析数据中的不同块并查找pHYs块,(我认为)您需要从该块中提取MacOSX生成的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,正如预期的那样。

krcsximq

krcsximq2#

我发现你现在可以通过clipboard.readBuffer("public.png")访问原始的PNG剪贴板数据来截图了。请看https://ocadaruma.hatenablog.com/entry/2023/01/29/091354了解它是如何工作的。

相关问题