真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何使用electron實(shí)現(xiàn)一個(gè)截屏工具-創(chuàng)新互聯(lián)

這篇文章將為大家詳細(xì)講解有關(guān)如何使用electron實(shí)現(xiàn)一個(gè)截屏工具,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿(mǎn)足客戶(hù)于互聯(lián)網(wǎng)時(shí)代的子長(zhǎng)網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

思路

electron 提供了截取屏幕的 API,可以輕松的獲取每個(gè)屏幕(存在外接顯示器的情況)和每個(gè)窗口的圖像信息。

  • 把圖片截取出來(lái),然后創(chuàng)建一個(gè)全屏的窗口蓋住整個(gè)屏幕,將截取的圖片繪制在窗口上,然后再覆蓋一層黑色半透明的元素,看起來(lái)就像屏幕定住了一樣;

  • 在窗口上增加交互制作選區(qū)的效果;

  • 點(diǎn)擊確定,利用 canvas 對(duì)應(yīng)選區(qū)的位置截取圖片內(nèi)容,寫(xiě)入剪貼板和保存圖片。

搭建項(xiàng)目

首先創(chuàng)建 package.json 填寫(xiě)項(xiàng)目的必要信息, 注意 main 為入口文件。

{
 "name": "electorn-capture-screen",
 "version": "1.0.0",
 "main": "main.js",
 "repository": "https://github.com/chrisbing/electorn-capture-screen.git",
 "author": "Chris",
 "license": "MIT",
 "scripts": {
 "start": "electron ."
 },
 "dependencies": {
 "electron": "^3.0.2"
 }
}

創(chuàng)建 main.js , 代碼來(lái)自 electron 官方文檔

const { app, BrowserWindow, ipcMain, globalShortcut } = require('electron')
const os = require('os')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win

function createWindow() {
 
 // 創(chuàng)建瀏覽器窗口。
 win = new BrowserWindow({ width: 800, height: 600 })

 // 然后加載應(yīng)用的 index.html。
 win.loadFile('index.html')

 // 打開(kāi)開(kāi)發(fā)者工具
 win.webContents.openDevTools()

 // 當(dāng) window 被關(guān)閉,這個(gè)事件會(huì)被觸發(fā)。
 win.on('closed', () => {
  // 取消引用 window 對(duì)象,如果你的應(yīng)用支持多窗口的話(huà),
  // 通常會(huì)把多個(gè) window 對(duì)象存放在一個(gè)數(shù)組里面,
  // 與此同時(shí),你應(yīng)該刪除相應(yīng)的元素。
  win = null
 })
}

// Electron 會(huì)在初始化后并準(zhǔn)備
// 創(chuàng)建瀏覽器窗口時(shí),調(diào)用這個(gè)函數(shù)。
// 部分 API 在 ready 事件觸發(fā)后才能使用。
app.on('ready', createWindow)

// 當(dāng)全部窗口關(guān)閉時(shí)退出。
app.on('window-all-closed', () => {
 // 在 macOS 上,除非用戶(hù)用 Cmd + Q 確定地退出,
 // 否則絕大部分應(yīng)用及其菜單欄會(huì)保持激活。
 if (process.platform !== 'darwin') {
  app.quit()
 }
})

app.on('activate', () => {
 // 在macOS上,當(dāng)單擊dock圖標(biāo)并且沒(méi)有其他窗口打開(kāi)時(shí),
 // 通常在應(yīng)用程序中重新創(chuàng)建一個(gè)窗口。
 if (win === null) {
  createWindow()
 }
})

創(chuàng)建 index.html , html 中放了一個(gè)按鈕, 用來(lái)觸發(fā)截屏操作




 
 Hello World!


Capture Screen


這樣一個(gè)簡(jiǎn)單的 electron 項(xiàng)目就完成了, 執(zhí)行 yarn start 或者 npm start 即可看到一個(gè)窗口, 窗口中有一個(gè)按鈕

如何使用electron實(shí)現(xiàn)一個(gè)截屏工具

觸發(fā)截屏

截屏是一個(gè)相對(duì)獨(dú)立的功能, 并且有可能會(huì)有全局快捷鍵以及菜單觸發(fā)等脫離窗口的情況, 所以截屏的觸發(fā)應(yīng)該放在 main 進(jìn)程中來(lái)實(shí)現(xiàn)

在 renderer 進(jìn)程中可以通過(guò) ipc 通訊來(lái)完成, 在頁(yè)面的代碼中使用 ipcRenderer 發(fā)送事件, 而在 main 中使用 ipcMain 接收事件

// index.html
	const { ipcRenderer } = require('electron')

	document.getElementById('js-capture').addEventListener('click', ()=>{
		ipcRenderer.send('capture-screen')
	})

在 main 進(jìn)程中接收 capture-screen 事件

// main.js

// 接收事件
ipcMain.on('capture-screen', captureScreen)

同時(shí)加入全局快捷鍵觸發(fā)和取消截屏

// main.js

// 注冊(cè)全局快捷鍵
// globalShortcut 需要在 app ready 之后
globalShortcut.register('CmdOrCtrl+Shift+A', captureScreen)
globalShortcut.register('Esc', () => {
 if (captureWin) {
  captureWin.close()
  captureWin = null
 }
})

通過(guò)快捷鍵和事件來(lái)觸發(fā)截屏方法 captureScreen , 接下來(lái)實(shí)現(xiàn)這個(gè)方法來(lái)創(chuàng)建一個(gè)截屏窗口

創(chuàng)建截屏窗口

截屏窗口是要?jiǎng)?chuàng)建一個(gè)全屏的窗口, 并且把屏幕圖片繪制在窗口上, 再通過(guò)鼠標(biāo)拖拽等交互操作選出特定區(qū)域的圖像.

第一步是要?jiǎng)?chuàng)建窗口

// main.js
let captureWin = null

const captureScreen = (e, args) => {
 if (captureWin) {
  return
 }
 const { screen } = require('electron')
 let { width, height } = screen.getPrimaryDisplay().bounds
 captureWin = new BrowserWindow({
  // window 使用 fullscreen, mac 設(shè)置為 undefined, 不可為 false
  fullscreen: os.platform() === 'win32' || undefined, // win
  width,
  height,
  x: 0,
  y: 0,
  transparent: true,
  frame: false,
  skipTaskbar: true,
  autoHideMenuBar: true,
  movable: false,
  resizable: false,
  enableLargerThanScreen: true, // mac
  hasShadow: false,
 })
 captureWin.setAlwaysOnTop(true, 'screen-saver') // mac
 captureWin.setVisibleOnAllWorkspaces(true) // mac
 captureWin.setFullScreenable(false) // mac

 captureWin.loadFile(path.join(__dirname, 'capture.html'))

 // 調(diào)試用
 // captureWin.openDevTools()

 captureWin.on('closed', () => {
  captureWin = null
 })

}

窗口需要覆蓋全屏, 并且完全置頂, 在 windows 下可以使用 fullscreen 來(lái)保證全屏, Mac 下 fullscreen 會(huì)把窗口移到單獨(dú)桌面, 所以采用了另外的辦法, 代碼注釋上標(biāo)注了不同系統(tǒng)的相關(guān)選項(xiàng), 具體內(nèi)容可以查看文檔

注意這里窗口加載了另外一個(gè) html 文件, 這個(gè)文件用來(lái)負(fù)責(zé)截屏和裁剪的一些交互工作

capture.html

首先 html 結(jié)構(gòu)

// capture.html

       

Bg : 截屏圖片 Mask : 一層灰色遮罩 Canvas : 繪制選中的圖片區(qū)域和邊框 Size info : 標(biāo)識(shí)截取范圍的尺寸 Toolbar : 操作按鈕, 用來(lái)取消和保存等 capture-renderer.js : js 代碼

@import "./assets/iconfont/iconfont.css";

html, body, div {
 margin: 0;
 padding: 0;
 box-sizing: border-box;
}

.mask {
 position: absolute;
 top: 0;
 left: 0;
 width: 100%;
 height: 100%;
 background: rgba(0, 0, 0, 0.6);
}

.bg {
 position: absolute;
 top: 0;
 left: 0;
 width: 100%;
 height: 100%;
}

.image-canvas {
 position: absolute;
 display: none;
 z-index: 1;
}

.size-info {
 position: absolute;
 color: #ffffff;
 font-size: 12px;
 background: rgba(40, 40, 40, 0.8);
 padding: 5px 10px;
 border-radius: 2px;
 font-family: Arial Consolas sans-serif;
 display: none;
 z-index: 2;
}

.toolbar {
 position: absolute;
 color: #343434;
 font-size: 12px;
 background: #f5f5f5;
 padding: 5px 10px;
 border-radius: 4px;
 font-family: Arial Consolas sans-serif;
 display: none;
 box-shadow: 0 0 20px rgba(0, 0, 0, 0.4);
 z-index: 2;
 align-items: center;
}

.toolbar .iconfont {
 font-size: 24px;
 padding: 2px 5px;
}

各個(gè)元素基本為 absolute 定位, 由 js 控制位置 按鈕使用了 iconfont , 所有涉及到的資源文件和完整項(xiàng)目可以到 GitHub - chrisbing/electorn-capture-screen: electron capture screen 中下載

截圖交互

如何使用electron實(shí)現(xiàn)一個(gè)截屏工具

完成的功能有截取指定區(qū)域圖片, 拖拽移動(dòng)和改變選區(qū)尺寸, 實(shí)時(shí)尺寸顯示和工具條

獲取屏幕截圖

// capture-renderer.js

const { ipcRenderer, clipboard, nativeImage, remote, desktopCapturer, screen } = require('electron')
const Event = require('events')
const fs = require('fs')

const { bounds: { width, height }, scaleFactor } = screen.getPrimaryDisplay()
const $canvas = document.getElementById('js-canvas')
const $bg = document.getElementById('js-bg')
const $sizeInfo = document.getElementById('js-size-info')
const $toolbar = document.getElementById('js-toolbar')

const $btnClose = document.getElementById('js-tool-close')
const $btnOk = document.getElementById('js-tool-ok')
const $btnSave = document.getElementById('js-tool-save')
const $btnReset = document.getElementById('js-tool-reset')

console.time('capture')
desktopCapturer.getSources({
 types: ['screen'],
 thumbnailSize: {
  width: width * scaleFactor,
  height: height * scaleFactor,
 }
}, (error, sources) => {
 console.timeEnd('capture')
 let imgSrc = sources[0].thumbnail.toDataURL()

 let capture = new CaptureRenderer($canvas, $bg, imgSrc, scaleFactor)
})

screen.getPrimaryDisplay() 可以獲取主屏幕的大小和縮放比例, 縮放比例在高分屏中適用, 在高分屏中屏幕的物理尺寸和窗口尺寸并不一致, 一般會(huì)有2倍3倍等縮放倍數(shù), 所以為了獲取到高清的屏幕截圖, 需要在屏幕尺寸基礎(chǔ)上乘以縮放倍數(shù)

desktopCapturer 獲取屏幕截圖的圖片信息, 獲取的是一個(gè)數(shù)組, 包含了每一個(gè)屏幕的信息, 這里呢暫時(shí)只處理了第一個(gè)屏幕的信息

獲取了截圖信息后創(chuàng)建 CaptureRenderer 進(jìn)行交互處理

CaptureRenderer

// capture-renderer.js
class CaptureRenderer extends Event {

 constructor($canvas, $bg, imageSrc, scaleFactor) {
  super()
 		 // ...

  this.init().then(() => {
   console.log('init')
  })
 }

 async init() {
  this.$bg.style.backgroundImage = `url(${this.imageSrc})`
  this.$bg.style.backgroundSize = `${width}px ${height}px`
  let canvas = document.createElement('canvas')
  let ctx = canvas.getContext('2d')
  let img = await new Promise(resolve => {
   let img = new Image()
   img.src = this.imageSrc
   if (img.complete) {
    resolve(img)
   } else {
    img.onload = () => resolve(img)
   }
  })

  canvas.width = img.width
  canvas.height = img.height
  ctx.drawImage(img, 0, 0)
  this.bgCtx = ctx
		 // ...
 }
	 
 // ...

 onMouseDrag(e) {
		 // ...
		 this.selectRect = {x, y, w, h, r, b}
  this.drawRect()
  this.emit('dragging', this.selectRect)
  // ...
 }

 drawRect() {
  if (!this.selectRect) {
   this.$canvas.style.display = 'none'
   return
  }
  const { x, y, w, h } = this.selectRect

  const scaleFactor = this.scaleFactor
  let margin = 7
  let radius = 5
  this.$canvas.style.left = `${x - margin}px`
  this.$canvas.style.top = `${y - margin}px`
  this.$canvas.style.width = `${w + margin * 2}px`
  this.$canvas.style.height = `${h + margin * 2}px`
  this.$canvas.style.display = 'block'
  this.$canvas.width = (w + margin * 2) * scaleFactor
  this.$canvas.height = (h + margin * 2) * scaleFactor

  if (w && h) {
   let imageData = this.bgCtx.getImageData(x * scaleFactor, y * scaleFactor, w * scaleFactor, h * scaleFactor)
   this.ctx.putImageData(imageData, margin * scaleFactor, margin * scaleFactor)
  }
  this.ctx.fillStyle = '#ffffff'
  this.ctx.strokeStyle = '#67bade'
  this.ctx.lineWidth = 2 * this.scaleFactor

  this.ctx.strokeRect(margin * scaleFactor, margin * scaleFactor, w * scaleFactor, h * scaleFactor)
  this.drawAnchors(w, h, margin, scaleFactor, radius)
 }

 drawAnchors(w, h, margin, scaleFactor, radius) {
  // ...
 }

 onMouseMove(e) {
  // ...
  document.body.style.cursor = 'move'
  // ...
 }

 onMouseUp(e) {
  this.emit('end-dragging')
  this.drawRect()
 }

 getImageUrl() {
  const { x, y, w, h } = this.selectRect
  if (w && h) {
   let imageData = this.bgCtx.getImageData(x * scaleFactor, y * scaleFactor, w * scaleFactor, h * scaleFactor)
   let canvas = document.createElement('canvas')
   let ctx = canvas.getContext('2d')
   ctx.putImageData(imageData, 0, 0)
   return canvas.toDataURL()
  }
  return ''
 }

 reset() {
  // ...
 }
}

代碼有點(diǎn)長(zhǎng), 由于篇幅的原因, 這里只列出了關(guān)鍵部分, 完整代碼請(qǐng)到 GitHub - chrisbing/electorn-capture-screen: electron capture screen 上查看

初始化時(shí)保存一份繪制了全部圖片的 canvas , 用來(lái)后續(xù)取選區(qū)部分圖片用

繪制過(guò)程中從 通過(guò) canvas 中的 getImageData 獲取圖片內(nèi)容 然后通過(guò) putImageData 繪制到顯示 canvas 中

附加內(nèi)容

在 CaptureRenderer 類(lèi)中處理了圖片的選取. 還需要工具條和尺寸信息

這一部分代碼和圖片選取關(guān)系不是很大, 所以在外部單獨(dú)處理, 通過(guò) CaptureRenderer 傳出的事件和一些屬性即可完成交互

// capture-renderer.js

let onDrag = (selectRect) => {
 $toolbar.style.display = 'none'
 $sizeInfo.style.display = 'block'
 $sizeInfo.innerText = `${selectRect.w} * ${selectRect.h}`
 if (selectRect.y > 35) {
  $sizeInfo.style.top = `${selectRect.y - 30}px`
 } else {
  $sizeInfo.style.top = `${selectRect.y + 10}px`
 }
 $sizeInfo.style.left = `${selectRect.x}px`
}
capture.on('start-dragging', onDrag)
capture.on('dragging', onDrag)

let onDragEnd = () => {
 if (capture.selectRect) {
  const { x, r, b, y } = capture.selectRect
  $toolbar.style.display = 'flex'
  $toolbar.style.top = `${b + 15}px`
  $toolbar.style.right = `${window.screen.width - r}px`
 }
}
capture.on('end-dragging', onDragEnd)

capture.on('reset', () => {
 $toolbar.style.display = 'none'
 $sizeInfo.style.display = 'none'
})

移動(dòng)過(guò)程中計(jì)算尺寸, 并且實(shí)時(shí)計(jì)算位置, 移動(dòng)過(guò)程中隱藏工具條

重置選區(qū)時(shí)隱藏工具條和尺寸標(biāo)識(shí)

保存剪貼板

// capture-renderer.js

const audio = new Audio()
audio.src = './assets/audio/capture.mp3'

let selectCapture = () => {
 if (!capture.selectRect) {
  return
 }
 let url = capture.getImageUrl()
 remote.getCurrentWindow().hide()

 audio.play()
 audio.onended = () => {
  window.close()
 }
 clipboard.writeImage(nativeImage.createFromDataURL(url))
 ipcRenderer.send('capture-screen', {
  type: 'complete',
  url,
 })
}

$btnOk.addEventListener('click', selectCapture)

通過(guò) nativeImage.createFromDataURL 創(chuàng)建圖片寫(xiě)入剪貼板, 通知 main 進(jìn)程截圖完畢, 并附帶圖片的 base64 url, 然后關(guān)閉窗口

保存到文件

// capture-renderer.js
$btnSave.addEventListener(‘click', () => {
 let url = capture.getImageUrl()

 remote.getCurrentWindow().hide()
 remote.dialog.showSaveDialog({
  filters: [{
   name: ‘Images',
   extensions: [‘png', ‘jpg', ‘gif']
  }]
 }, function (path) {
  if (path) {
   fs.writeFile(path, new Buffer(url.replace(‘data:image/png;base64,', ‘'), ‘base64'), function () {
    ipcRenderer.send(‘capture-screen', {
     type: ‘complete',
     url,
     path,
    })
    window.close()
   })
  } else {
   ipcRenderer.send(‘capture-screen', {
    type: ‘cancel',
    url,
   })
   window.close()
  }
 })
})

利用 remote.dialog.showSaveDialog 選擇保存文件名, 然后通過(guò) fs 模塊寫(xiě)入文件

最終整體目錄結(jié)構(gòu)

├── index.html
├── lib // 截圖核心代碼
│  ├── assets // font 和 聲音資源
│  ├── capture-main.js // main 中截圖部分代碼
│  ├── capture-renderer.js // 截圖交互代碼
│  └── capture.html // 截圖 html
├── main.js 
└── package.json

關(guān)于“如何使用electron實(shí)現(xiàn)一個(gè)截屏工具”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線(xiàn),公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。


分享文章:如何使用electron實(shí)現(xiàn)一個(gè)截屏工具-創(chuàng)新互聯(lián)
瀏覽地址:http://weahome.cn/article/csjddh.html

在線(xiàn)咨詢(xún)

微信咨詢(xún)

電話(huà)咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部