Using the Electron framework to weed out images
Ready, Steady, Go
An article on setting up the Electron Framework [3] was published in Linux Magazine a few months ago, so I mention the preparation only briefly and then head on directly to processing the photo folders.
The following commands install the Electron framework on Ubuntu:
sudo apt-get install npm nodejs-legacy
The additional nodejs-legacy
package only installs some symlinks that many older node modules need during build and execution. In a fresh directory, then run
npm init npm install electron --save-dev
to create a new project that not only installs the Electron framework locally, but also adds its dependencies to its dependency list, helping adopters to modify and rebuild the code to their heart's content. The npm init
command prompts the user to enter some project parameters, such as the application name, its version, or the author name (Figure 2). The --save-dev
option of the npm install
statement appends the name of the installed package to the devDependencies
list in package.json
. For comparison, --save
would list the package as a run-time dependency.
![](/var/linux_magazin/storage/images/issues/2018/216/programming-snapshot-electron/figure-2/735454-1-eng-US/Figure-2_large.png)
If you also add the following to the scripts
section inside package.json
,
"start": "electron ."
the application can be launched later by using npm start
. Electron then initially loads the main.js
start script in Listing 1 [4] (specified in the configuration file under main
) and passes it to the Node.js interpreter for execution.
Courage to be Different
As is well known, the asynchronous functional approach used by Node.js means a very different programming style compared with "normal" languages like Python or Perl. Instead of sequentially processing calls, Node.js code often adds a callback to a function call. The function later resumes execution by calling it at the end.
The GUI code builds a state machine, between whose states the code jumps back and forth, as controlled by events. At the same time, the event loop always needs to watch out for new events such as mouse clicks, to which it must respond promptly. This would not work if the code were just blocked for a while because it was reading a large file from disk.
The code in Listing 1 does not execute anything at first but waits until the node environment reports the ready
event. If this occurs, it starts the callback from line 25 and first submits a web page to the renderer process for display with createWindow()
. This happens from line 8 and with an object of the BrowserWindow
class, whose loadURL()
method is given the path to the index.html
file in Listing 2.
Listing 1
main.js
01 const {app,globalShortcut,BrowserWindow} = 02 require('electron'); 03 const path = require('path'); 04 const url = require('url'); 05 06 let win; 07 08 function createWindow(){ 09 win = new BrowserWindow({ 10 width:800, height:600}); 11 12 win.loadURL(url.format({ 13 pathname: 14 path.join(__dirname, 'index.html'), 15 protocol: 'file:', slashes: true 16 })); 17 18 win.webContents.openDevTools(); 19 20 win.on('closed', () => { 21 win = null; 22 }); 23 } 24 25 app.on('ready', () => { 26 createWindow(); 27 globalShortcut.register('l', () => { 28 win.webContents.send('nextImage'); 29 }); 30 globalShortcut.register('h', () => { 31 win.webContents.send('prevImage'); 32 }); 33 globalShortcut.register('d', () => { 34 win.webContents.send('deleteImage'); 35 }); 36 win.webContents.send('prevImage'); 37 }); 38 39 app.on('will-quit', () => { 40 ['h','l','d'].forEach(function(key){ 41 globalShortcut.unregister(key); 42 }); 43 }); 44 45 app.on('window-all-closed', () => { 46 app.quit(); 47 });
Listing 2
index.html
01 <html> 02 <head> </head> 03 04 <body> 05 <h1>iNuke My Photos</h1> 06 07 <script> 08 require('./renderer.js'); 09 </script> 10 11 <img id="image"></img> 12 13 </body> 14 </html>
At the same time, Listing 1 uses the global variable win
to store a reference to the browser window. It can reset the variable during later callbacks, as being performed by the handler of the closed
event, which gets triggered by the windowing system, and handles freeing up memory before shutting down the program.
During the debug phase of a new Electron application, it is extremely useful to open Chromium's debug window in the browser's main window using openDevTools()
(line 18) and either read the warnings at the command line or analyze the HTML of the dynamically refreshed web page (Figure 3).
![](/var/linux_magazin/storage/images/issues/2018/216/programming-snapshot-electron/figure-3/735457-1-eng-US/Figure-3_large.png)
Short and Sweet
Intercepting keyboard input is also a task of the main process in main.js
. The register
calls in lines 27, 30, and 33 ensure that the user can move to the next image with L and to the previous image with H (just as you move left or right in Vim) and delete the displayed image with D.
Among other things, these keystroke commands affect the displayed web page, which is why the main process main.js
sends them as events to the renderer process in Listing 3 via IPC and win.webContents.send()
. The renderer process starts out at the very beginning of the main process in Listing 1. It loads the index.html
file (Listing 2) into the browser in lines 12 to 16, which in turn executes the renderer's JavaScript (Listing 3) in line 8 of Listing 2 via require(./renderer.js)
.
Listing 3
renderer.js
01 loadImage = require('blueimp-load-image'); 02 fs = require( 'fs' ); 03 ipc = require('electron').ipcRenderer; 04 05 images = []; 06 images_idx = -1; 07 08 function displayImage(file) { 09 loaded = loadImage(file, function(img) { 10 scaled_img = loadImage.scale( 11 img, {maxWidth: 600}); 12 scaled_img.id = "image"; 13 node = window.document.getElementById( 14 'image'); 15 node.replaceWith(scaled_img); 16 } ); 17 } 18 19 function scroll(direction){ 20 images_idx += direction; 21 if(images_idx > images.length-1){ 22 images_idx = images.length-1; 23 }else if(images_idx<0) { 24 images_idx = 0; 25 } 26 displayImage( images[ images_idx ] ); 27 } 28 29 function deleteImage() { 30 fs.unlink(images[ images_idx ]); 31 images.splice(images_idx, 1); 32 if(images.length == 0) { 33 console.log("That's it. Good-bye!"); 34 require('electron').remote.app.quit(); 35 } 36 scroll(-1); 37 } 38 39 dir = "images"; // change to process.cwd() 40 fs.readdir(dir, function(err, files) { 41 if( err ) { 42 console.error("readdir:", err); 43 require('electron').remote.app.quit(); 44 } 45 files.forEach(function(file, index) { 46 images.push( dir + "/" + file ); 47 }); 48 scroll(0); 49 } ); 50 51 ipc.on('nextImage', () => { scroll(1); }); 52 ipc.on('prevImage', () => { scroll(-1); }); 53 ipc.on('deleteImage', deleteImage);
« Previous 1 2 3 4 Next »
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
![Learn More](https://www.linux-magazine.com/var/linux_magazin/storage/images/media/linux-magazine-eng-us/images/misc/learn-more/834592-1-eng-US/Learn-More_medium.png)
News
-
NVIDIA Released Driver for Upcoming NVIDIA 560 GPU for Linux
Not only has NVIDIA released the driver for its upcoming CPU series, it's the first release that defaults to using open-source GPU kernel modules.
-
OpenMandriva Lx 24.07 Released
If you’re into rolling release Linux distributions, OpenMandriva ROME has a new snapshot with a new kernel.
-
Kernel 6.10 Available for General Usage
Linus Torvalds has released the 6.10 kernel and it includes significant performance increases for Intel Core hybrid systems and more.
-
TUXEDO Computers Releases InfinityBook Pro 14 Gen9 Laptop
Sporting either AMD or Intel CPUs, the TUXEDO InfinityBook Pro 14 is an extremely compact, lightweight, sturdy powerhouse.
-
Google Extends Support for Linux Kernels Used for Android
Because the LTS Linux kernel releases are so important to Android, Google has decided to extend the support period beyond that offered by the kernel development team.
-
Linux Mint 22 Stable Delayed
If you're anxious about getting your hands on the stable release of Linux Mint 22, it looks as if you're going to have to wait a bit longer.
-
Nitrux 3.5.1 Available for Install
The latest version of the immutable, systemd-free distribution includes an updated kernel and NVIDIA driver.
-
Debian 12.6 Released with Plenty of Bug Fixes and Updates
The sixth update to Debian "Bookworm" is all about security mitigations and making adjustments for some "serious problems."
-
Canonical Offers 12-Year LTS for Open Source Docker Images
Canonical is expanding its LTS offering to reach beyond the DEB packages with a new distro-less Docker image.
-
Plasma Desktop 6.1 Released with Several Enhancements
If you're a fan of Plasma Desktop, you should be excited about this new point release.