background

Before looking at the next face++ interface, do a simple demo of face fusion, by the way look at other interfaces, see a picture text interface, suddenly brainwave.

When I see some interesting pictures and texts, I want to type them down and put them in Evernote or my moments. But the key here is to manually type, if you take a screenshot, just copy the text to the clipboard. So you have this application, and it’s not that complicated to implement. Everyone with me over it, like can star~

start

Initialize a electron application

Build your first electron app by referring to the electron website

$ yarn add electron -D
Copy the code

The directory structure

├─ src
│  └─ main.js    # entry file, main process│ └ ─ index. HTML# Render the page of the process
Copy the code

Add the following to the scripts field of package.json

"start": "electron src/main.js"
Copy the code

Entrance to the file

The electron process is divided into the main process and the render process. The rendering process is the front-end UI rendering process, which can be compared to a TAB page in Chrome. A TAB is a process. The render process is managed by the main process, which acts as a Chrome window and closes the window in which all TAB pages are still present. Some function modules can only be called by the main process, and also by the renderer (for example, screenshots can only be called by the renderer).

Our requirements are

  • All you need is a single tray called tray (upper right corner of MAC, lower right corner of Win), without opening a specific window

  • CmdOrCtrl+Shift+V is the screenshot shortcut key
const { app, BrowserWindow,  globalShortcut ,Tray,Menu,ipcMain} = require('electron')

const shell = require('electron').shell;

const path=require('path')

let win

let srcPath=path.join(__dirname,".. /src")

let clip=true
// Create the tray
function createTray () {
    tray = new Tray(`${srcPath}/images/font.png`) // Specify the path to the image, available on Github
    const contextMenu = Menu.buildFromTemplate([ //Menu types include checkbox, radio, normal, etc
        { label: 'clip'.type: 'checkbox',click(){ clip=! clip },checked:true },
        { label: 'about', click(){
            // Open the default browser
            shell.openExternal('https://github.com/yokiyokiyoki/clip-font-app'); }}, {label: 'exit',click(){
            app.quit()
        }}
    ])
    tray.setToolTip('Tutu literate')
    tray.setContextMenu(contextMenu)
    // Register shortcut key
    globalShortcut.register('CmdOrCtrl+Shift+V', captureScreen)
    globalShortcut.register('Esc', () = > {if (win) {
            win.close()
            win = null}})}function createCaptureWindow() {
    // Create a browser window, only one is allowed (must be created because only renderers can take screenshots)
    if(win)return console.info('There can only be one CaptureWindow')
    const { screen } = require('electron') // Because ready can be introduced
    let { width, height } = screen.getPrimaryDisplay().bounds
    win = new BrowserWindow({ 
        fullscreen: process.platform ! = ='darwin' || 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.webPreferences: {
            webSecurity: false // You can load local files. If you do not load local files, you will receive an error: you are not allowed to load local files
        }
    })

    win.setAlwaysOnTop(true.'screen-saver') // mac
    win.setVisibleOnAllWorkspaces(true) // mac
    win.setFullScreenable(false) // mac

    // Then load the app's index.html.
    win.loadFile(path.join(__dirname,'.. /index.html'))

    // Open the developer tool
    win.webContents.openDevTools()

    // This event is raised when the window is closed.
    win.on('closed', () => {
        win = null
    })
}
app.on('ready', createTray)
Exit when all Windows are closed.
app.on('window-all-closed', () = > {// On macOS, unless the user explicitly exits with Cmd + Q,
    // Otherwise, most apps and their menu bar remain active.
    if(process.platform ! = ='darwin') {
        app.quit()
    }
})

app.on('activate', () = > {if (win === null) {
        createCaptureWindow()
    }
})

function captureScreen(){
    if(clip){
        createCaptureWindow()
    }
}
Copy the code

Write index. HTML

Above we opened index.html through the main loadFile process. Here we can make a very shallow UI with size information, toolbars, etc. It’s based on full-screen HTML. Why do you do that? You can think about it


      
<html>
  <head>
    <meta charset="UTF-8">
    <title>screenshots</title>
  </head>
  <style>
  html.body.div {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
  .bg {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
  .mask {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.6);
  }
  .rect {
    position: absolute;
    display: node;
    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{
  display: inline-block;
  cursor: pointer;
}
  </style>
  <body>
    <! -- Mask layer with grey background -->
    <div class="bg"></div>
    <div id="mask" class="mask"></div>
    <canvas class="rect"></canvas>
    <! -- Size information -->
    <div class="size-info">200 * 200</div>
    <! --toolbar-->
    <div class="toolbar">
      <div class="iconfont icon-close" >Shut down</div>
      <div class="iconfont icon-check" >confirm</div>
      <div class="iconfont icon-literacy" >identify</div>
    </div>
    <script src="./src/js/capture.js"></script> <! -- I haven't written it yet.
  </body>
</html>
Copy the code

At this point we can start development with NPM start, see the page with the shortcut CmdOrCtrl+Shift+V, and the tray is in the upper left corner. If an error occurs, please review the above procedure.

The screenshot function is realized

We put the logic in capture.js

Female, Electron provides a screen capture API, which is expected of you. It’s easy to get images of each screen and window. Can go to understand ~ first

The principle (actually very simple, just two canvas) :

1. The dataURL generated by capturing the full screen through electron is stored in a special canvas (let’s call it the full screen Canvas) with drawImage (dataURL and Cavas love each other), and then the dataURL is assigned to the background, so that the blank background image, Full screen appearance (illusion), plus translucent mask.

2. Make a selection from another canvas (canvas) and use the mouse position to determine — getImageData (x, Y, W, H). The selection is inside the imgData in the full canvas. And I’m going to import the data from the full screen Canvas into this canvas — putImageData(imgData, x, y)

const {  desktopCapturer, screen } = require('electron')
const { bounds: { width, height } } = screen.getPrimaryDisplay()
const path=require('path')

const {Draw} = require(`${__dirname}/src/js/draw.js`)

desktopCapturer.getSources({
    types: ['screen'].thumbnailSize: {
        width, height
    }
}, async(error, sources) => {
    if (error) return console.log(error)
    let screenImgUrl = sources[0].thumbnail.toDataURL() / / get dataURL
    
    let bg=document.querySelector('.bg')
    let rect=document.querySelector('.rect')
    let sizeInfo=document.querySelector('.size-info')
    let toolbar=document.querySelector('.toolbar')
    /** * Draw class * ScreenImgUrl is a base64 snapshot of the entire screen * bg is the background DOM * Width is the width of the screen * rect is the selection Canvas * sizeInfo size information container * Toolbar */
    let draw=new Draw(screenImgUrl,bg,width,height,rect,sizeInfo,toolbar)
    document.addEventListener('mousedown',draw.startRect.bind(draw))
    document.addEventListener('mousemove',draw.drawingRect.bind(draw))
    document.addEventListener('mouseup',draw.endRect.bind(draw))
})
Copy the code

The Draw class writes how the screenshot selection is implemented, which is a bit long, so you can go to Github. It is mainly to draw a rectangle with the mouse, and then locate the data of the full-screen canvas to a specific location and import it.

IPCMain
ipcRenderer

// The renderer sends the message
ipcRenderer.send('clip-page', { type: type, message: msg })

// The main process receives
ipcMain.on('clip-page', (event, {type,msg}) => {
    if(type==='close') {if (win) {
            win.close()
            win = null}}})Copy the code

packaging

We tried it out in development mode and we think we should be fine. At this time to package the application on each platform for the actual use of users ~

Here we use the electron Builder, create a script command in package.json, and add a build field (automatically read by electron Builder).

"scripts": {
    "start": "electron src/main.js"."build": "electron-builder",},"build": {/ / name
    "productName": "clip-font-app"."appId": "Personal. DesktopApp. ClipFont. 1.0.0"."directories": {
        // Package directory
      "output": "dist"
    },
    "files": [
    // All files
      ". / / * * * *"].// Windows installation wizard
    "nsis": {
      "oneClick": false."allowElevation": true."allowToChangeInstallationDirectory": true."installerIcon": "src/images/icon.ico"."uninstallerIcon": "src/images/icon.ico"."installerHeaderIcon": "src/images/icon.ico"."createDesktopShortcut": true."createStartMenuShortcut": true."shortcutName": "ClipFont"
    },
    "dmg": {
      "contents": [{"x": 410."y": 150."type": "link".// Whether to drag to the application directory
          "path": "/Applications"
        },
        {
          "x": 130."y": 150."type": "file"}},"mac": {
      "icon": "src/images/icon.icns"
    },
    "win": {
      "icon": "src/images/icon.ico"."target": [{"target": "nsis"."arch": [
            "ia32"]]}},"linux": {
      "icon": "src/images"
    },
    // The download source is taobao mirror, some domestic reasons may lead to failure
    "electronDownload": {
      "mirror": "http://npm.taobao.org/mirrors/electron/"}}Copy the code

Then we NPM run build, since I use a MAC, and then packaged down is DMG ~, double click DMG install.

The effect

Let’s use the shortcut key (CmdOrCtrl+Shift+V) to identify ~

subsequent

Of course, how could a screenshot toolbar be so simple?

  • Toolbars are complete and will include functions such as downloads
  • Supports multi-window screenshots
  • Drag and drop the node