使用Electron開發一個吸色工具的心路歷程

爲何要(zuo)

」世界上只有一種英雄主義,那就是認清本身的髮際線以後依然熱愛擼碼「 -- 歐大強·羅蘭node

Electron是一個很是有趣的開源項目,「它可讓你使用純 JavaScript 調用豐富的原生(操做系統) APIs 來創造桌面應用」。光看這官方簡介就讓人不住躍躍欲試,再加上市面上沒找到能讓我中意的桌面吸色工具,因此我決定使用Electron來開發一款。
下載地址:git

需求與界面

個人軟件,界面必定要好看,LOGO必定要大氣,主色調要那種低沉性感又不失莊重,氣勢磅礴的黑。github

desgin

(獻醜了。果真設計師不是隨便就能作的)chrome

功能大體包括如下幾點canvas

  • 支持快捷鍵操做並可自定義。
  • 有歷史選色記錄。
  • 能自由切換色值。
  • 在已知透明度和背景色的條件下計算出當前取色器的rgba色值。
  • 支持最小化到托盤

基本思路

Electron沒有API能夠直接拿到當前指針所在位置的色值,可是提供了獲取桌面資源的方法。在執行取色操做時使用desktopCapturer將當前桌面截圖,而後在canvas上展現並使用getImageData() 獲取指定色值。Easy。
windows

prossess

遇到的問題

關於Electron的介紹網絡有不少,上手難度也不算高,線程之間的關係與操做還有API文檔寫的很是詳細,但這不意味着你(zuo)起來就能一路順風了。api

Global變量沒法獲取

經過ipc和global咱們很容易就能實現一個簡易的狀態管理機制,在這裏我碰到了第一個坑。
由於remote複製對象而不是提供引用,因此在渲染進程中操做的global對象須要提早在主進程中定義初始值。
main process:瀏覽器

global.sharedObj = {prop1: null};
複製代碼

renderer process:網絡

remote.getGlobal('sharedObj').prop1 = 125;
複製代碼

使用desktopCapturer截圖有色差

經過desktopCapturer.getSources()API咱們能夠獲得一個DesktopCapturerSource對象,再配合getUserMedia咱們能夠很方便的獲取當前可用資源。app

// In the renderer process.
const { desktopCapturer } = require('electron')

desktopCapturer.getSources({ types: ['window', 'screen'] }, (error, sources) => {
  ...
  navigator.mediaDevices.getUserMedia({
    ...
    video: {
      mandatory: {
        chromeMediaSource: 'desktop',
        chromeMediaSourceId: sources[0].id,
        ...
      }
    }
  }).then((stream) => {
    const video = document.querySelector('video')
    video.srcObject = stream
  }).catch((e) => ...)
})

複製代碼

以上是官方給的使用文檔,將video的第一幀繪製到canvas上便成功對當前桌面進行截圖。但事情並無這麼簡單,在我閱片無數的雙眼下,任何細微的差異都無處遁行,使用getUserMedia獲得的圖像居然有色差

diff

我測算了一下,截圖獲得的圖片和原圖相比,綠色通道的值要高一些,因此我猜想形成色差的緣由多是因爲瀏覽器使用的是 sRGB色域,而顯示器使用的是aRGB色域(但願有大佬能幫忙指正)。
雖然經過 DesktopCapturerSource對象上的 thumnail(NativeImage)能直接獲得當前桌面的縮略圖(截圖)而且沒有色差, 可是desktopCapturer在工做中是會阻塞進程的,不推薦直接經過 thumnail來獲取百分百比例的桌面截圖。因此最後我選擇使用 desktop-screenshot這個第三方node庫來實現截圖步驟。

寫入文件路徑報錯

我使用了lowdb這個node庫來儲存設置的快捷鍵和歷史色值,開發的時候一切正常,可打包後在Mac上運行起來就會報錯EROFS: read-only file system

error

未簽名的app彷佛在mac上很不招待見,好在Electron提供了 app.getPath(name)來獲取文件路徑的,咱們沒法肯定用戶會將軟件放到哪一個目錄,因此我建議將須要被修改的文件放入系統文件夾或臨時文件夾。

app.getPath(name) // Electron
  or
  os.tmpdir() // node原生模塊得到臨時文件路徑
複製代碼

打包優化

除了儘量減小dependencies的依賴以外,基本無解。別問,問就是100M起。

結尾

雖然這是一個簡單的項目,還有不少沒來得及深刻發掘。
雖然常伴小坑,但總的來講瑕不掩瑜,體驗仍是至關到位的。 若是你也想體驗一把桌面應用開發,Electron是個很是靠譜的選擇。
github

參考資料:

相關文章
相關標籤/搜索