├── .gitignore ├── .vscode └── launch.json ├── README.md ├── demo ├── main.js └── package.json ├── index.js ├── package.json └── src ├── main.js ├── preload.js └── tools.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log 4 | npm-debug.log.* 5 | thumbs.db 6 | !.gitkeep 7 | .temp_capture 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug Main Process", 6 | "type": "node", 7 | "request": "launch", 8 | "cwd": "${workspaceRoot}", 9 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron", 10 | "program": "${workspaceRoot}/index.js" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electron-capture 2 | 3 | > An extension for Electron's BrowserWindow, Make it have the ability to capture full page. 4 | 5 | [![npm version](https://img.shields.io/npm/v/electron-capture.svg)](https://www.npmjs.com/package/electron-capture) 6 | 7 | ### Why I create this repo 8 | I tried a lots of npm packages, but no one can add the feature (full page capture) for my electron-application. So I code this. 9 | 10 | ### Install 11 | 12 | ``` sh 13 | npm install electron-capture --save 14 | ``` 15 | 16 | ### Usage 17 | 18 | ``` javascript 19 | require('electron-capture') 20 | 21 | mainWindow = new BrowserWindow({ 22 | width: 1366, 23 | height: 768, 24 | resizable: true, 25 | webPreferences: { 26 | preload: __dirname + '/node_modules/electron-capture/src/preload.js' 27 | } 28 | }) 29 | mainWindow.loadURL('https://www.google.com/') 30 | 31 | mainWindow.captureFullPage(function(imageStream){ 32 | // return an image Stream 33 | imageStream.pipe(fs.createWriteStream('example.png')); 34 | }) 35 | 36 | ``` 37 | 38 | [Demo](https://github.com/GeoffZhu/electron-capture/tree/master/demo) 39 | 40 | -------------------------------------------------------------------------------- /demo/main.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const Electron = require('electron') 3 | const { BrowserWindow, app } = require('electron') 4 | require('electron-capture') 5 | 6 | let mainWindow = null 7 | 8 | function createWindow () { 9 | mainWindow = new BrowserWindow({ 10 | width: 1366, 11 | height: 2768, 12 | resizable: true, 13 | webPreferences: { 14 | preload: __dirname + '/node_modules/electron-capture/src/preload.js' 15 | } 16 | }) 17 | mainWindow.loadURL('https://www.google.com/') 18 | // init BrowserWindow 19 | 20 | // when need full capture, call function captureFullPage 21 | mainWindow.captureFullPage(function(imageStream){ 22 | // return image Stream 23 | imageStream.pipe(fs.createWriteStream('example.png')); 24 | }) 25 | } 26 | 27 | app.on('ready', createWindow) 28 | 29 | app.on('window-all-closed', () => { 30 | if (process.platform !== 'darwin') { 31 | app.quit() 32 | } 33 | }) 34 | 35 | app.on('activate', () => { 36 | if (mainWindow === null) { 37 | createWindow() 38 | } 39 | }) -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "geoffzhu1992@gmail.com", 3 | "main": "main.js", 4 | "scripts": { 5 | "start": "electron ./main.js" 6 | }, 7 | "dependencies": { 8 | "electron": "^1.6.2", 9 | "electron-capture": "^1.1.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron') 2 | const fs = require('fs') 3 | const { BrowserWindow, app } = require('electron') 4 | require('./src/main') 5 | 6 | let mainWindow = null 7 | 8 | function createWindow () { 9 | mainWindow = new BrowserWindow({ 10 | width: 1366, 11 | height: 2768, 12 | resizable: true, 13 | webPreferences: { 14 | preload: __dirname + '/src/preload.js', 15 | webSecurity: true 16 | } 17 | }) 18 | mainWindow.loadURL('https://www.google.com/') 19 | mainWindow.openDevTools() 20 | 21 | mainWindow.captureFullPage(function(imageStream){ 22 | // return image Stream 23 | imageStream.pipe(fs.createWriteStream('example.png')); 24 | }) 25 | } 26 | 27 | app.on('ready', createWindow) 28 | 29 | app.on('window-all-closed', () => { 30 | if (process.platform !== 'darwin') { 31 | app.quit() 32 | } 33 | }) 34 | 35 | app.on('activate', () => { 36 | if (mainWindow === null) { 37 | createWindow() 38 | } 39 | }) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-capture", 3 | "description": "A small webpage capture extension for electron Application. Get a screenshot of the full webpage.", 4 | "version": "1.1.3", 5 | "author": "geoffzhu1992@gmail.com", 6 | "main": "src/main.js", 7 | "scripts": { 8 | "dev": "electron --debug ./index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/GeoffZhu/electron-capture" 13 | }, 14 | "dependencies": { 15 | "pixelsmith": "^2.1.1" 16 | }, 17 | "keywords": [ 18 | "electron", 19 | "capture", 20 | "screenshot", 21 | "electron-extension" 22 | ], 23 | "bugs": { 24 | "url": "https://github.com/GeoffZhu/electron-capture/issues" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const Pixelsmith = require('pixelsmith') 3 | const { BrowserWindow, ipcMain, app } = require('electron') 4 | const { fsExistsSync } = require('./tools') 5 | 6 | let tempDir = app.getPath('userData') + '/.temp_capture', pixelsmith = new Pixelsmith(), canvas = null, contentSize = null, captureTimes = 1 7 | let targetWindow = null, callback = null, options = {} 8 | 9 | ipcMain.on('start-capture', function(events){ 10 | targetWindow.webContents.send('get-content-size') 11 | }) 12 | ipcMain.on('return-content-size', function (events, size) { 13 | contentSize = size 14 | captureTimes = Math.ceil(contentSize.height/contentSize.windowHeight) 15 | targetWindow.webContents.send('move-page-to', 1) 16 | }) 17 | ipcMain.on('return-move-page', function (events, page) { 18 | let options = { 19 | x: 0, 20 | y: 0, 21 | width: contentSize.windowWidth, 22 | height: contentSize.windowHeight 23 | } 24 | if (page === captureTimes) { 25 | options.height = contentSize.height - ((captureTimes - 1) * contentSize.windowHeight) 26 | options.y = contentSize.windowHeight - options.height 27 | } 28 | targetWindow.capturePage(options, function (image) { 29 | if (!fsExistsSync(tempDir)) { 30 | fs.mkdirSync(tempDir) 31 | } 32 | fs.writeFile(tempDir + '/' + page + '.png', image.toPNG(), function(err){ 33 | if (page !== captureTimes) { 34 | targetWindow.webContents.send('move-page-to', page + 1) 35 | } else { 36 | flattenPNG() 37 | } 38 | }) 39 | }) 40 | }) 41 | 42 | function flattenPNG () { 43 | let fileNames = [], y = 0, canvasHeight = 0, canvasWidth = 0, scrollBarWidth = 0 44 | for (var i = 1 ; i <= captureTimes; i++) { 45 | fileNames.push(tempDir + '/' + i + '.png') 46 | } 47 | pixelsmith.createImages(fileNames, function handleImages (err, imgs) { 48 | // If there was an error, throw it 49 | if (err) { console.log(err) } 50 | if (canvasWidth === 0) canvasWidth = imgs[0].width 51 | scrollBarWidth = canvasWidth/contentSize.width*contentSize.scrollBarWidth 52 | imgs.forEach(function(img) { 53 | canvasHeight += img.height 54 | }) 55 | // Create a canvas that fits images 56 | canvas = pixelsmith.createCanvas(canvasWidth - scrollBarWidth, canvasHeight) 57 | // Add the images to canvas 58 | imgs.forEach(function(img, index){ 59 | canvas.addImage(imgs[index], 0, y); 60 | y += imgs[index].height 61 | }) 62 | // Export canvas to image 63 | var resultStream = canvas['export']({format: 'png'}) 64 | callback(resultStream) 65 | }) 66 | } 67 | 68 | BrowserWindow.prototype.captureFullPage = function(_callback, _options){ 69 | targetWindow = this 70 | callback = _callback 71 | options = _options || {} 72 | canvas = null 73 | this.webContents.executeJavaScript(` 74 | var ipcRender = require('electron').ipcRenderer; 75 | ipcRender.send('start-capture'); 76 | `) 77 | } -------------------------------------------------------------------------------- /src/preload.js: -------------------------------------------------------------------------------- 1 | var ipcRender = require('electron').ipcRenderer; 2 | 3 | ipcRender.on('get-content-size', function() { 4 | var height = Math.max( document.body.scrollHeight, document.body.offsetHeight, 5 | document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight ); 6 | ipcRender.send('return-content-size', { 7 | width: window.innerWidth, 8 | height: height, 9 | windowHeight: window.innerHeight, 10 | windowWidth: window.innerWidth, 11 | scrollBarWidth: window.innerWidth - document.body.clientWidth 12 | }); 13 | }); 14 | 15 | ipcRender.on('move-page-to', function(events, page) { 16 | console.log('page:', page) 17 | window.scrollTo(0, window.innerHeight * (page - 1) ) 18 | setTimeout(function() { 19 | ipcRender.send('return-move-page', page); 20 | }, 100) 21 | }); -------------------------------------------------------------------------------- /src/tools.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | exports.fsExistsSync = function (path) { 4 | try { 5 | fs.accessSync(path, fs.F_OK); 6 | }catch (e) { 7 | return false; 8 | } 9 | return true; 10 | } --------------------------------------------------------------------------------