首页 / Electron 入门教程 / screen 与 nativeImage:获取屏幕信息与处理图像

Electron 入门教程

screen 与 nativeImage:获取屏幕信息与处理图像

本教程共 45 篇 · 第 25 篇 · 更新于 2026-08-03

ElectronscreennativeImage显示器图像

25. screen 与 nativeImage:屏幕信息与图像处理

本节目标

  • screen 获取主显示器、所有显示器与工作区尺寸。
  • 理解物理像素与 DIP 坐标的区别。
  • nativeImage 从路径、缓冲、DataURL 创建图像。
  • 对图像做缩放、裁剪并导出为 PNG/JPEG/DataURL。
  • nativeImage 用于托盘与窗口图标等场景。

25-1 screen 模块的基础

screen 模块用来查询屏幕相关的信息:有哪些显示器、每个显示器多大、可用工作区(扣除任务栏后的区域)是多少。它在主进程里运行,并且必须在 appready 事件发出后才能使用。

和渲染进程里的 window.screen 不同,Electron 的 screen 是来自 electron/main 的独立模块。在渲染进程或 DevTools 里,window.screen 是浏览器保留的 DOM 属性,不能用 require 覆盖它。

使用 screen 最常见的目的,是让窗口刚好铺满某个显示器的可用区域,或者把新窗口放到外接显示器上。

// 主进程 main.js
const { app, BrowserWindow, screen } = require('electron/main')

app.whenReady().then(() => {
  const primary = screen.getPrimaryDisplay()
  const { width, height } = primary.workAreaSize

  const win = new BrowserWindow({ width, height })
  win.loadFile('index.html')
})

这里用的是 workAreaSize 而不是 sizeworkAreaSize 扣除了系统任务栏、Dock 等占用的空间,窗口不会被这些系统 UI 遮挡。

25-2 多显示器与坐标系

当你连接了外接显示器,screen.getAllDisplays() 会返回所有显示器的数组。每个显示器对象带 bounds(在全局坐标系里的位置和尺寸)等字段。

下面的例子找到「非主显示器」的外接屏,把窗口放到它的左上角偏移处。

// 主进程 main.js
const { app, BrowserWindow, screen } = require('electron/main')

app.whenReady().then(() => {
  const displays = screen.getAllDisplays()
  const external = displays.find((d) => d.bounds.x !== 0 || d.bounds.y !== 0)

  if (external) {
    const win = new BrowserWindow({
      x: external.bounds.x + 50,
      y: external.bounds.y + 50
    })
    win.loadFile('index.html')
  }
})

这里要理解两种坐标:物理屏幕点(硬件原始像素)和设备无关点 DIP(按 DPI 缩放后的虚拟点)。Electron 返回的坐标默认是 DIP,getCursorScreenPoint() 返回的也是 DIP 点。Windows 和 Linux 上还有 screenToDipPoint / dipToScreenPoint 做两者换算,但 Wayland 下支持有限。

除了上述方法,还有 getDisplayNearestPoint(point)getDisplayMatching(rect) 用来按坐标或区域找最近的显示器。

25-3 screen 的事件

screen 是一个 EventEmitter,会在显示器变化时发出事件。最常用的三个是:

  • display-added:有新显示器接入。
  • display-removed:显示器被移除。
  • display-metrics-changed:某个显示器的 boundsworkAreascaleFactorrotation 等发生变化。

这些事件适合用来做「多屏布局自适应」,比如窗口所在的屏幕被拔掉后,把窗口移回主屏。

// 主进程 main.js
const { screen } = require('electron/main')

screen.on('display-metrics-changed', (event, display, changedMetrics) => {
  console.log('显示器指标变化:', changedMetrics)
})

25-4 nativeImage 的创建方式

nativeImage 提供了一套统一的图像操作接口,常用于托盘图标、窗口图标、通知图标等。它的创建方式有多种,按来源区分:

  • createFromPath(path):从 PNG/JPEG 文件创建,路径不存在时返回空图像。
  • createFromBuffer(buffer[, options]):从内存缓冲创建,会先尝试按 PNG/JPEG 解码。
  • createFromDataURL(dataURL):从 base64 的 DataURL 创建。
  • createEmpty():创建一个空的透明图像。
  • createFromBitmap(buffer, options):从原始位图数据创建,需指定宽高。
// 主进程 main.js
const { nativeImage } = require('electron/main')

const fromPath = nativeImage.createFromPath('/Users/me/icon.png')
const fromUrl = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgo...')
const empty = nativeImage.createEmpty()

console.log('是否为空:', empty.isEmpty())

Electron 接受图像参数的 API,既可以传文件路径字符串,也可以传 NativeImage 实例。两者等价,但用实例能进一步做缩放、裁剪等处理。

25-5 缩放、裁剪与导出

拿到 NativeImage 后,可以做常见变换。resize(options) 缩放图像,只给 widthheight 之一时会保持原宽高比。crop(rect) 按矩形区域裁剪,返回新的 NativeImage

// 主进程 main.js
const { nativeImage } = require('electron/main')

const image = nativeImage.createFromPath('/Users/me/photo.png')

// 缩放到宽 100,高度按比例自动
const resized = image.resize({ width: 100 })

// 裁出左上角 50x50 的区域
const cropped = image.crop({ x: 0, y: 0, width: 50, height: 50 })

// 取尺寸信息
console.log(resized.getSize())

导出方面,toPNG()toJPEG(quality) 把图像编码为 Buffer,toDataURL() 导出为 DataURL 字符串,方便直接塞进 <img src>

// 主进程 / preload.js
const { nativeImage } = require('electron/main')

const image = nativeImage.createFromPath('/Users/me/icon.png')
const pngBuffer = image.toPNG()
const dataUrl = image.toDataURL()

25-6 高密度屏与模板图像

在支持高 DPI 的屏幕上(如 macOS Retina),推荐为同一图标提供多套尺寸。约定是在文件名后加 @2x@3x 后缀,例如 icon.pngicon@2x.png,Electron 会自动按屏幕密度选择。

Windows 上还支持 ICO 图标,建议包含 16/32/48/256 等多种尺寸以保证清晰度。macOS 的菜单栏图标可用「模板图像」:文件名以 Template 结尾(如 trayTemplate.png),或以代码 setTemplateImage(true) 标记,它只含黑白与透明度,能自动适配明暗菜单栏。

// 主进程 main.js
const { nativeImage } = require('electron/main')

const trayIcon = nativeImage.createFromPath('/Users/me/trayTemplate.png')
trayIcon.setTemplateImage(true)

25-7 在渲染进程安全地使用图像

nativeImage 文档标注主进程和渲染进程都可用,但若开启了上下文隔离,应在 preload 里调用并通过 contextBridge 暴露。下面演示把剪贴板图像导出为 DataURL 给页面显示。

// 预加载脚本 preload.js
const { contextBridge, ipcRenderer } = require('electron')
const { clipboard, nativeImage } = require('electron/main')

contextBridge.exposeInMainWorld('imageApi', {
  clipboardToDataURL: () => {
    const img = clipboard.readImage()
    return img.isEmpty() ? null : img.toDataURL()
  }
})
// 渲染进程 renderer.js
const url = window.imageApi.clipboardToDataURL()
if (url) document.getElementById('preview').src = url

25-8 多比例表示与动态构建

NativeImage 还提供 getScaleFactors(),返回当前图像包含的所有比例表示(如 [1, 2])。如果你要针对不同屏幕密度手动补一套图,可以用 addRepresentation(options) 往一个空图像上追加表示。

这在程序化生成图标时很有用:你不一定有现成的多尺寸文件,却可以根据一份高清缓冲生成 1x、2x 两套,交给系统按屏幕挑选。

// 主进程 main.js
const { nativeImage } = require('electron/main')

const hiRes = nativeImage.createFromPath('/Users/me/icon@2x.png')
const factors = hiRes.getScaleFactors()
console.log('包含的比例:', factors)

// 程序化增补表示
const img = nativeImage.createEmpty()
img.addRepresentation({
  scaleFactor: 2,
  buffer: hiRes.toBitmap()
})

理解了 screennativeImage 之后,你已经能为窗口、托盘、通知都配上合适的图标,也能按显示器工作区精确摆放窗口,这是做出「像样桌面应用」的基础能力。

补充一点:Windows 与 macOS 支持 createThumbnailFromPath(path, size),可直接为任意文件生成缩略图(macOS、Windows 可用),非常适合做文件预览列表。它返回 Promise,解析为 NativeImage,省去你手动解码。

DPI 后缀方面,除了 @2x,Electron 还识别 @1x@1.5x@3x@4x 等一系列比例。把同一图标的不同尺寸放在同一目录,文件名不带后缀地传给 API,系统会按当前屏幕密度自动挑选最匹配的那张,既清晰又省内存。

实际项目里,最常见的做法是在应用启动时根据主显示器信息决定窗口初始大小。比如先用 screen.getPrimaryDisplay() 拿到 workAreaSize,再按七成或八成比例创建窗口,这样既不会过小难以使用,也不会超出可用区域被任务栏遮挡。配合 screen.on('display-metrics-changed'),还能在用户拖动窗口到另一块屏幕、或改变分辨率时,实时调整窗口尺寸或重新居中,体验更顺滑。

getScaleFactorsaddRepresentation 的组合也值得一提:当你只有一张高清原图时,可以生成多种比例表示,确保无论用户屏幕是 1x 还是 3x,图标都锐利不发虚。

常见误区

不要把 getPrimaryDisplay().size 当作可用区域。它包含任务栏等系统 UI 占用的空间,窗口铺满后会被遮挡,应当用 workAreaSize

不要忽略 createFromPath 可能返回空图像。路径错误时不会抛异常,而是返回空图像,使用前最好用 isEmpty() 判断。

v43 起 toBitmap() 默认把像素数据归一化到 sRGB 色彩空间。如果你需要保留原始色彩空间,要在 options 里显式传入图像原本的 colorSpace,否则颜色可能和预期不一致。