1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      如何使用electron實(shí)現(xiàn)一個(gè)截屏工具

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

      創(chuàng)新互聯(lián)建站專注于瓊山網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠為您提供瓊山營銷型網(wǎng)站建設(shè),瓊山網(wǎng)站制作、瓊山網(wǎng)頁設(shè)計(jì)、瓊山網(wǎng)站官網(wǎng)定制、微信平臺小程序開發(fā)服務(wù),打造瓊山網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供瓊山網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。

      思路

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

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

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

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

      搭建項(xiàng)目

      首先創(chuàng)建 package.json 填寫項(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 , 代碼來自 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')
      
       // 打開開發(fā)者工具
       win.webContents.openDevTools()
      
       // 當(dāng) window 被關(guān)閉,這個(gè)事件會被觸發(fā)。
       win.on('closed', () => {
        // 取消引用 window 對象,如果你的應(yīng)用支持多窗口的話,
        // 通常會把多個(gè) window 對象存放在一個(gè)數(shù)組里面,
        // 與此同時(shí),你應(yīng)該刪除相應(yīng)的元素。
        win = null
       })
      }
      
      // Electron 會在初始化后并準(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 上,除非用戶用 Cmd + Q 確定地退出,
       // 否則絕大部分應(yīng)用及其菜單欄會保持激活。
       if (process.platform !== 'darwin') {
        app.quit()
       }
      })
      
      app.on('activate', () => {
       // 在macOS上,當(dāng)單擊dock圖標(biāo)并且沒有其他窗口打開時(shí),
       // 通常在應(yīng)用程序中重新創(chuàng)建一個(gè)窗口。
       if (win === null) {
        createWindow()
       }
      })

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

      
      
      
       
       Hello World!
      
      
      Capture Screen
      
      
      

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

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

      觸發(fā)截屏

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

      在 renderer 進(jìn)程中可以通過 ipc 通訊來完成, 在頁面的代碼中使用 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
      
      // 注冊全局快捷鍵
      // globalShortcut 需要在 app ready 之后
      globalShortcut.register('CmdOrCtrl+Shift+A', captureScreen)
      globalShortcut.register('Esc', () => {
       if (captureWin) {
        captureWin.close()
        captureWin = null
       }
      })

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

      創(chuàng)建截屏窗口

      截屏窗口是要?jiǎng)?chuàng)建一個(gè)全屏的窗口, 并且把屏幕圖片繪制在窗口上, 再通過鼠標(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 來保證全屏, Mac 下 fullscreen 會把窗口移到單獨(dú)桌面, 所以采用了另外的辦法, 代碼注釋上標(biāo)注了不同系統(tǒng)的相關(guān)選項(xiàng), 具體內(nèi)容可以查看文檔

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

      capture.html

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

      // capture.html
      
      
       
       
       
       

      Bg : 截屏圖片 Mask : 一層灰色遮罩 Canvas : 繪制選中的圖片區(qū)域和邊框 Size info : 標(biāo)識截取范圍的尺寸 Toolbar : 操作按鈕, 用來取消和保存等 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ū)域圖片, 拖拽移動和改變選區(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() 可以獲取主屏幕的大小和縮放比例, 縮放比例在高分屏中適用, 在高分屏中屏幕的物理尺寸和窗口尺寸并不一致, 一般會有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)長, 由于篇幅的原因, 這里只列出了關(guān)鍵部分, 完整代碼請到 GitHub - chrisbing/electorn-capture-screen: electron capture screen 上查看

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

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

      附加內(nèi)容

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

      這一部分代碼和圖片選取關(guān)系不是很大, 所以在外部單獨(dú)處理, 通過 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'
      })

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

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

      保存剪貼板

      // 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)

      通過 nativeImage.createFromDataURL 創(chuàng)建圖片寫入剪貼板, 通知 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 選擇保存文件名, 然后通過 fs 模塊寫入文件

      最終整體目錄結(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)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯(cuò),請把它分享出去讓更多的人看到。


      網(wǎng)頁題目:如何使用electron實(shí)現(xiàn)一個(gè)截屏工具
      網(wǎng)址分享:http://www.ef60e0e.cn/article/gegigj.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        九龙城区| 温泉县| 浦江县| 峨山| 云林县| 墨江| 黄龙县| 鹤壁市| 惠来县| 阳原县| 来安县| 驻马店市| 石渠县| 安多县| 洪洞县| 岳西县| 丹江口市| 大新县| 宜城市| 依兰县| 兴仁县| 壶关县| 常德市| 定南县| 渭源县| 锡林浩特市| 会东县| 托克逊县| 三都| 合作市| 咸丰县| 梅河口市| 英德市| 石渠县| 得荣县| 德钦县| 白银市| 望谟县| 大理市| 济南市| 高阳县|