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