Aprende a crear una captura de pantalla de su aplicación o la pantalla con Electron fácilmente.

Creación de capturas de pantalla de tu aplicación o la pantalla en Electron Framework

Aunque requerir la creación de una captura de pantalla en tu aplicación no es tan habitual, saber cómo hacerlo no te hará daño. Esta función es realmente útil para todas las aplicaciones que deseen, por ejemplo, un informe de errores detallado. Es posible que un mensaje de error de la consola no ayude en muchos casos, sin embargo, una imagen podría salvar el día.

En este artículo, aprenderá cómo crear una captura de pantalla en Electron desde diferentes áreas en el escritorio fácilmente usando el desktopCapture componente integrado.

Captura de pantalla completa

En caso de que necesite tomar una captura de pantalla de toda la pantalla, el módulo desktopCapturer hará el trabajo por usted. Para manejar la captura de pantalla completa, use la siguiente función:

const {desktopCapturer} = require('electron');

/**
 * Cree una captura de pantalla de toda la pantalla utilizando el módulo desktopCapturer de Electron.
 *
 * @param callback {Function} callback receives as first parameter the base64 string of the image
 * @param imageFormat {String} Format of the image to generate ('image/jpeg' or 'image/png')
 **/
function fullscreenScreenshot(callback, imageFormat) {
    var _this = this;
    this.callback = callback;
    imageFormat = imageFormat || 'image/jpeg';
    
    this.handleStream = (stream) => {
        // Crear etiqueta de video oculta
        var video = document.createElement('video');
        video.style.cssText = 'position:absolute;top:-10000px;left:-10000px;';

        
        
        // Evento conectado a la transmisión
        video.onloadedmetadata = function () {
            // Set video ORIGINAL height (screenshot)
            video.style.height = this.videoHeight + 'px'; // videoHeight
            video.style.width = this.videoWidth + 'px'; // videoWidth

            video.play();

            // Crear canvas
            var canvas = document.createElement('canvas');
            canvas.width = this.videoWidth;
            canvas.height = this.videoHeight;
            var ctx = canvas.getContext('2d');
            // Draw video on canvas
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

            if (_this.callback) {
                // Guardar captura de pantalla en base64
                _this.callback(canvas.toDataURL(imageFormat));
            } else {
                console.log('Need callback!');
            }

            // Eliminar etiqueta de video oculta
            video.remove();
            try {
                // Destroy connect to stream
                stream.getTracks()[0].stop();
            } catch (e) {}
        }
        
        video.srcObject = stream;
        document.body.appendChild(video);
    };

    this.handleError = function(e) {
        console.log(e);
    };

    desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => {
        console.log(sources);
        
        for (const source of sources) {
            // Filter: main screen
            if ((source.name === "Entire screen") || (source.name === "Screen 1") || (source.name === "Screen 2")) {
                try{
                    const stream = await navigator.mediaDevices.getUserMedia({
                        audio: false,
                        video: {
                            mandatory: {
                                chromeMediaSource: 'desktop',
                                chromeMediaSourceId: source.id,
                                minWidth: 1280,
                                maxWidth: 4000,
                                minHeight: 720,
                                maxHeight: 4000
                            }
                        }
                    });

                    _this.handleStream(stream);
                } catch (e) {
                    _this.handleError(e);
                }
            }
        }
    });
}

La función utilizará el desktopCapturemódulo para crear una captura de pantalla de toda la pantalla. Se espera como primer parámetro una función (la devolución de llamada) que será invocada cuando la captura de pantalla esté lista para ser manipulada. Opcionalmente, puede proporcionar el formato de la imagen de resultado como segundo parámetro con el tipo de contenido ( image/pngimage/jpeg).

Uso

El uso de esta función es simple, puede incluirlo en su documento html y usarlo desde allí:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>My Electron Screenshot App</title>
    </head>
    <body>
        <p>Testing screenshots in Electron :3</p>
        <img id="my-preview"/>
        <input id="trigger" value="Fullscreen screenshot" type="button"/>

        <script>
            //* Aquí la función de captura de pantalla completa *//
            
            document.getElementById("trigger").addEventListener("click", function(){
                fullscreenScreenshot(function(base64data){
                    // Dibujar imagen en la etiqueta img
                    document.getElementById("my-preview").setAttribute("src", base64data);
                },'image/png');
            },false);
        </script>
    </body>
</html>

La ejecución del fragmento anterior en electron, debería producir algo similar a:

Electron fullscreen screenshot

Impresionante, dulce y simple, ¿no?

Creando una captura de pantalla de su aplicación Electron

Para crear una captura de pantalla de solo su aplicación, usaremos el mismo método pero con un par de modificaciones:

const {desktopCapturer} = require('electron');

/**
* Cree una captura de pantalla de su aplicación electrónica. Puede modificar qué proceso renderizar en la línea condicional # 61.
* En este caso, filtrado utilizando el título del documento.
*
* @param callback {Function} callback recibe como primer parámetro la cadena base64 de la imagen
* @param imageFormat {String} Format of the image to generate ('image/jpeg' or 'image/png')
**/
function appScreenshot(callback,imageFormat) {
    var _this = this;
    this.callback = callback;
    imageFormat = imageFormat || 'image/jpeg';
    
    this.handleStream = (stream) => {
        // Create hidden video tag
        var video = document.createElement('video');
        video.style.cssText = 'position:absolute;top:-10000px;left:-10000px;';
        // Event connected to stream
        video.onloadedmetadata = function () {
            // Set video ORIGINAL height (screenshot)
            video.style.height = this.videoHeight + 'px'; // videoHeight
            video.style.width = this.videoWidth + 'px'; // videoWidth

            video.play();

            // Crear canvas
            var canvas = document.createElement('canvas');
            canvas.width = this.videoWidth;
            canvas.height = this.videoHeight;
            var ctx = canvas.getContext('2d');
            // Draw video on canvas
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

            if (_this.callback) {
                // Save screenshot to jpg - base64
                _this.callback(canvas.toDataURL(imageFormat));
            } else {
                console.log('Need callback!');
            }

            // Remove hidden video tag
            video.remove();

            try {
                // Destroy connect to stream
                stream.getTracks()[0].stop();
            } catch (e) {}
        }

        video.srcObject = stream;
        document.body.appendChild(video);
    };

    this.handleError = function(e) {
        console.log(e);
    };

    desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => {
        console.log(sources);
        
        for (const source of sources) {
            // Filter: main screen
            if (source.name === document.title) {
                try{
                    const stream = await navigator.mediaDevices.getUserMedia({
                        audio: false,
                        video: {
                            mandatory: {
                                chromeMediaSource: 'desktop',
                                chromeMediaSourceId: source.id,
                                minWidth: 1280,
                                maxWidth: 4000,
                                minHeight: 720,
                                maxHeight: 4000
                            }
                        }
                    });

                    _this.handleStream(stream);
                } catch (e) {
                    _this.handleError(e);
                }
            }
        }
    });
}

En este caso, en el  desktopCapturer.getSourcesmétodo vamos a cargar tanto la ventana como la pantalla. Esto proporcionará un objeto con una estructura similar a:

List sources chrome and electron

El objeto por sí solo contiene todas las ventanas activas en el proceso de cromo (aplicaciones de google chrome y electron). Puede utilizar el identificador de cada objeto (nombre) para elegir qué proceso se utilizará para crear la captura de pantalla.

En este caso, como queremos crear una captura de pantalla de nuestra aplicación, debe filtrar por el título de la aplicación ( "My Electron Screenshot App") utilizando la document.titlepropiedad que se utiliza en el fragmento para identificar su aplicación.

Uso

El siguiente fragmento muestra cómo crear una captura de pantalla de su propia aplicación fácilmente usando la función appScreenshot:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>My Electron Screenshot App</title>
    </head>
    <body>
        <p>Testing screenshots in Electron :3</p>
        <img id="my-preview"/>
        <input id="trigger" value="Fullscreen screenshot" type="button"/>

        <script>
            //* Here the appScreenshot function *//
            
            document.getElementById("trigger").addEventListener("click", function(){
                appScreenshot(function(base64data){
                    // Draw image in the img tag
                    document.getElementById("my-preview").setAttribute("src", base64data);
                },'image/png');
            },false);
        </script>
    </body>
</html>

La ejecución del fragmento anterior en electron, debería producir algo similar a:

Electron application screenshot

Nota: si te enfrentas a una pantalla negra (eso también nos pasa a nosotros, como puedes ver la aplicación tiene el estilo de Windows 10 pero la captura de pantalla tiene el estilo Aero debido a la bandera --disable-d3d11 para evitar la pantalla negra) usando este método, lee más sobre el problema y cómo resolverlo en el área de Problemas conocidos.

Captura de pantalla con dimensiones especificadas

Si desea especificar las coordenadas de la pantalla donde se debe tomar la captura de pantalla, lamento decepcionarlo, porque eso no es posible de forma nativa . Sin embargo, puede utilizar un pequeño truco para lograr su objetivo . ¡Cree una captura de pantalla completa y recórtela con un módulo de manipulación de imágenes de terceros!

En el siguiente ejemplo, vamos a tomar una captura de pantalla completa (proporcionada por la primera función) y vamos a recortar el área de nuestra aplicación (la aplicación electron) con la ubicación de la ventana de acuerdo con la pantalla utilizando el módulo jimp que no requiere ninguna dependencia y funciona con javascript puro:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Working with Screnshots!</title>
</head>
<body>
    <div>
        <img id="image-preview" />
        <input type="button" id="create-screenshot" />
    </div>
    <script>
        /**
         * Create a screenshot of our app from a  fullscreenshot cropping it with Jimp module !
         */
        document.getElementById("create-screenshot").addEventListener("click", function() {
            var Jimp = require("jimp");

            fullscreenScreenshot(function(base64data){
                // add to buffer base64 image instead of saving locally in order to manipulate with Jimp
                var encondedImageBuffer = new Buffer(base64data.replace(/^data:image\/(png|gif|jpeg);base64,/,''), 'base64');

                var height = window.innerHeight;
                var width = window.innerWidth;
                var distanceX = window.screenLeft;
                var distanceY = window.screenTop;
                var screenDimensions = screen.getPrimaryDisplay().size;
                var screenHeight = screenDimensions.height;
                var screenWidth = screenDimensions.width;

                Jimp.read(encondedImageBuffer, function (err, image) {
                    if (err) throw err;

                    // Show the original width and height of the image in the console
                    console.log(image.bitmap.width, image.bitmap.height);

                    // Resize the image to the size of the screen
                    image.resize(screenWidth, screenHeight)
                    // Crop image according to the coordinates
                    // add some margin pixels for this example
                    image.crop(distanceX + 10, distanceY - 10, width + 10, height + 50)
                    // Get data in base64 and show in img tag
                    .getBase64('image/jpeg', function(err,base64data){
                        document.getElementById("image-preview").setAttribute("src", base64data);
                        //console.log(data);
                    });
                });
            },"image/jpeg");
        }, false);
    </script>
</body>
</html>

Y el resultado debería ser algo similar a:

Electron screenshop with specific dimensions cropped

Tenga en cuenta que este módulo se ha escrito en Javascript puro y no requiere ninguna dependencia nativa, por lo que es algo lento. Depende de usted implementar cualquier módulo nativo para recortar la imagen a sus necesidades.

Problemas conocidos

En algunos dispositivos, puede enfrentar el problema de la pantalla negra, informado en este problema en Github :

Black screen electron screenshot

La única solución conocida y funcional es iniciar su aplicación con algunos argumentos adicionales para evitar el uso de DX11 o la aceleración de la GPU usando las banderas si  --disable-d3d11o  --disable-gpu.

En el siguiente ejemplo, agregaremos la bandera en el  package.jsondel proyecto en la instrucción de inicio del elemento scripts (observe el --disable-d3d11parámetro en la inicialización de la aplicación):

{
    "name": "electron-quick-start",
    "version": "1.0.0",
    "description": "A minimal Electron application",
    "main": "main.js",
    "scripts": {
        "start": "electron . --disable-d3d11"
    },
    "repository": {
        "type": "git",
        "url": "git+https://github.com/electron/electron-quick-start.git"
    },
    "keywords": [
        "Electron",
        "quick",
        "start",
        "tutorial"
    ],
    "author": "GitHub",
    "license": "CC0-1.0",
    "bugs": {
        "url": "https://github.com/electron/electron-quick-start/issues"
    },
    "homepage": "https://github.com/electron/electron-quick-start#readme",
    "devDependencies": {
        "electron-prebuilt": "^1.2.0"
    },
    "dependencies": {
        "electron-dl": "^1.3.0"
    }
}

Luego inicie la aplicación como siempre la usa npm start y eso debería funcionar (en modo de depuración que debería simular una instrucción myapp.exe --argument), recuerde probar solo con 1 y luego con ambos hasta que funcione.

Que te diviertas !


Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores