个性化阅读
专注于IT技术分析

在Electron框架中创建你的应用或屏幕的屏幕截图

本文概述

尽管在你的应用中要求创建屏幕截图并不常见, 但是知道如何做不会对你造成伤害。此功能对于每个需要的应用程序都非常有用, 例如, 详细的错误报告!控制台错误消息在许多情况下可能无济于事, 但是, 映像可以节省很多时间。

在本文中, 你将学习如何使用desktopCapture内置组件轻松地从Desktop的不同区域在Electron中创建屏幕截图。

全屏截图

如果你需要截取整个屏幕的屏幕截图, 请使用desktopCapturer模块为你完成此工作。要处理全屏截图, 请使用以下功能:

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

/**
 * Create a screenshot of the entire screen using the desktopCapturer module of 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) => {
        // 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();

            // Create 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 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 === "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);
                }
            }
        }
    });
}

该函数将使用desktopCapture模块创建整个屏幕的屏幕截图。它期望将第一个参数作为函数(回调), 当准备好操作屏幕截图时将调用该函数。 (可选)你可以提供结果图像的格式作为内容类型(image / png或image / jpeg)的第二个参数。

用法

该函数的用法很简单, 你可以将其包含在html文档中, 然后从那里使用:

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

在Electron中执行前一个代码片段时, 应产生类似于以下内容的内容:

Electron全屏截图

太棒了, 甜美又简单吗?

创建你的Electron应用的屏幕截图

要仅创建你的应用的屏幕截图, 我们将使用相同的方法, 但要进行一些修改:

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

/**
* Create a screenshot of your electron app. You can modify which process to render in the conditional line #61.
* In this case, filtered using the title of the document.
*
* @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 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();

            // Create 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);
                }
            }
        }
    });
}

在这种情况下, 我们将在desktopCapturer.getSources方法中加载窗口和屏幕。这将为对象提供类似于以下内容的结构:

列出铬和Electron的来源

该对象本身包含铬过程中的所有活动窗口(谷歌铬和Electron应用程序)。你可以使用每个对象(名称)的标识符来选择将使用哪个进程来创建屏幕截图。

在这种情况下, 由于我们要创建应用程序的屏幕截图, 因此需要使用摘要中的document.title属性按应用程序的标题(“我的Electron屏幕快照应用程序”)进行过滤, 以识别你的应用程序。

用法

以下代码段显示了如何使用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>

在Electron中执行前一个代码片段时, 应产生类似于以下内容的内容:

Electron应用截图

注意:如果你遇到黑屏(我们也遇到了这种情况, 因为你可以看到该应用程序具有Windows 10风格, 但由于–disable-d3d11标志可防止黑屏, 因此屏幕截图具有Aero风格), 请使用此方法, 在”已知问题”区域中了解有关该问题以及如何解决它的更多信息。

具有指定尺寸的屏幕截图

如果你想指定应该截取屏幕截图的屏幕坐标, 那么对不起你, 我感到很抱歉, 因为这本来是不可能的。但是, 你可以使用一些技巧来实现你的目标。创建一个全屏快照并使用第三方图像处理模块对其进行裁剪!

在下面的示例中, 我们将使用全屏快照(由第一个功能提供), 并使用jimp模块根据屏幕根据屏幕位置裁剪应用程序(Electron应用程序)的区域不需要任何依赖关系, 并且可以使用纯JavaScript:

<!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>

结果应该类似于:

裁剪了特定尺寸的Electron屏幕商店

请注意, 该模块是用纯Javascript编写的, 不需要任何本机依赖, 因此它运行起来很慢。由你决定实施任何本机模块, 以便根据需要裁剪图像。

已知的问题

在某些设备中, 你可能会遇到黑屏问题, 此问题在Github中报告:

黑屏Electron截图

唯一有效的解决方案是使用一些额外的参数启动应用程序, 以使用标志–disable-d3d11或–disable-gpu阻止DX11的使用或GPU加速。

在以下示例中, 我们将在scripts元素的开始指令中将标记添加到项目的package.json中(请注意, 应用程序初始化时使用–disable-d3d11参数):

{
    "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"
    }
}

然后像往常一样使用npm start启动应用程序, 这应该可以解决问题(在调试模式下应该模拟myapp.exe –argument指令), 请记住仅尝试使用1, 然后再尝试使用两者, 直到它起作用为止。

玩得开心 !

赞(0)
未经允许不得转载:srcmini » 在Electron框架中创建你的应用或屏幕的屏幕截图

评论 抢沙发

评论前必须登录!