JavaScript/NodeJS 和 Electron 中的图像 DPI?
Image DPI in JavaScript/NodeJS and Electron?
我正在使用 Electron 构建一个主要用于 Mac OS X 的应用程序。用户可以将图像拖放到页面上,页面会创建一个 <img>
带有拖放图像的源路径,用户看到图像。
问题
如果用户在 Retina 显示屏上截取屏幕截图,然后将图像拖放到页面上,图像将以双倍大小显示。我需要以某种方式知道以其自然尺寸的一半显示此图像。
可能的解决方案
我相信如果我检查它的 DPI,我应该能够可靠地判断图像是否是视网膜图像。在 Mac 上的预览应用程序中,我可以看到图像是 144 DPI。本质上,如果 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, or for JPGs look for FFD8FFE000104A464946000101
as mentioned here。我现在遇到的问题是当从剪贴板粘贴图像时尝试使用 Electron 的 NativeImage。
如果我从剪贴板粘贴 PNG,然后执行 nativeImage.toPng().toString('hex')
,输出如下:
89504e470d0a1a0a0000000d49484452000001fc000001680806000000b2a54946000005c249444154789cedd5410dc03010c0b0ae448f3f8a0dc554a9b111e4976766de05005c6d9f0e0000fe67f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f80010f0014a0204ec5f3e63f20000000049454e44ae426082
在这个字符串的什么地方可以找到 DPI 信息?
编辑和更新 2: 我想知道这是否是 Electron 中的错误。当我从预览中复制 144 PPI 的图像并将其粘贴到我的应用程序中,然后将其复制出我的应用程序并将其粘贴到新的预览 window 中时,它变为 72 PPI。有没有可能是Electron把这些信息剥离了?
块
应@robertklep 的要求,这里是块的屏幕截图(抱歉,我在我的应用程序中覆盖了复制,所以我现在不能真正复制文本)。
初始图像
copied/pasted之后
您显示的输出看起来是原始 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
,正如预期的那样。
我正在使用 Electron 构建一个主要用于 Mac OS X 的应用程序。用户可以将图像拖放到页面上,页面会创建一个 <img>
带有拖放图像的源路径,用户看到图像。
如果用户在 Retina 显示屏上截取屏幕截图,然后将图像拖放到页面上,图像将以双倍大小显示。我需要以某种方式知道以其自然尺寸的一半显示此图像。
可能的解决方案我相信如果我检查它的 DPI,我应该能够可靠地判断图像是否是视网膜图像。在 Mac 上的预览应用程序中,我可以看到图像是 144 DPI。本质上,如果 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, or for JPGs look for FFD8FFE000104A464946000101
as mentioned here。我现在遇到的问题是当从剪贴板粘贴图像时尝试使用 Electron 的 NativeImage。
如果我从剪贴板粘贴 PNG,然后执行 nativeImage.toPng().toString('hex')
,输出如下:
89504e470d0a1a0a0000000d49484452000001fc000001680806000000b2a54946000005c249444154789cedd5410dc03010c0b0ae448f3f8a0dc554a9b111e4976766de05005c6d9f0e0000fe67f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f8001060f80010f0014a0204ec5f3e63f20000000049454e44ae426082
在这个字符串的什么地方可以找到 DPI 信息?
编辑和更新 2: 我想知道这是否是 Electron 中的错误。当我从预览中复制 144 PPI 的图像并将其粘贴到我的应用程序中,然后将其复制出我的应用程序并将其粘贴到新的预览 window 中时,它变为 72 PPI。有没有可能是Electron把这些信息剥离了?
块
应@robertklep 的要求,这里是块的屏幕截图(抱歉,我在我的应用程序中覆盖了复制,所以我现在不能真正复制文本)。
初始图像
copied/pasted之后
您显示的输出看起来是原始 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
,正如预期的那样。