Electron 应用实现截图并编辑功能

这篇具有很好参考价值的文章主要介绍了Electron 应用实现截图并编辑功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Electron 应用实现截图并编辑功能

Electron 应用如何实现截屏功能,有两种思路,作为一个框架是否可以通过框架实现截屏,另一种就是 javaScript 结合 html 中画布功能实现截屏。
在初步思考之后,本文优先探索使用 Electron 实现截屏功能。作为一个成熟的框架,如果能够完成截屏,那自然是已经考虑了各种会出现的问题。
Electron 想要截屏还是要用到 desktopCapturer API。这个 API 也是用来实现录屏。
首先创建一个项目,直接 clone angular-electron。

环境

  • Angular@13.3.1
  • Electron@18.0.1
  • ngx-img-cropper@11.0.0

流程:

1.渲染进程向主进程取截屏的数据。
2.主进程获取截屏数据,并返回。
3.渲染进程取到数据后,将数据转为图片显示在页面上。
4.页面编辑图片并获取新的图片数据保存到本地。

首先在 home.component.ts 中绑定一个点击事件,向主进程发送一个消息取得录屏的初始数据:

async getScreensht() {
    let data = await this.electron.ipcRenderer.invoke("get-screenshot");
}

在主进程 main.ts 中,首先获取当前屏幕(可能存在多个屏幕),再取得当前屏幕的截屏数据:

先看取得截屏数据的方法:

let sources = await desktopCapturer.getSources({ types: ['screen'], thumbnailSize: thumbSize });

结果如下(只有一个屏幕数据,如果有两个屏幕,则有两条数据,依次类推):

 [
  {
    name: 'Entire Screen',
    id: 'screen:0:0',
    thumbnail: NativeImage {
      toPNG: [Function: toPNG],
      toJPEG: [Function: toJPEG],
      toBitmap: [Function: toBitmap],
      getBitmap: [Function: getBitmap],
      toDataURL: [Function: toDataURL],
      ...
    },
    display_id: '2528732444',
    appIcon: null
  }
]

这个结果中有一个参数 display_id,代表着对应的屏幕。那么怎么知道截屏哪个屏幕呢?需要利用鼠标点击事件,鼠标在哪个屏幕点击则截屏哪个屏幕。
鼠标点击位于当前屏幕的窗口,方法如下,通过 BrowserWindow 找到聚焦的窗口,再根据位置判断当前窗口位于哪个屏幕:

// 获取当前窗口所在屏幕
function getCurrentScreen() {
  let focusedWindow = BrowserWindow.getFocusedWindow();
  let currentBounds =  focusedWindow.getBounds();
  let currentDisplay = screen.getAllDisplays().find((display) => {
    return (
      currentBounds.x >= display.bounds.x &&
      currentBounds.x < display.bounds.x + display.bounds.width &&
      currentBounds.y >= display.bounds.y &&
      currentBounds.y < display.bounds.y + display.bounds.height
    );
  });
  return currentDisplay;
}

以上方法返回的结果如下,可以看到其中的 id 参数与上文中的 display_id 一致。
由此可以从 desktopCapturer.getSources() 返回的多个数据中找到当前点击的屏幕。

{
  id: 2528732444,
  bounds: { x: 0, y: 0, width: 1920, height: 1080 },
  workArea: { x: 0, y: 0, width: 1920, height: 1040 },
  accelerometerSupport: 'unknown',
  ...
}

遗憾的是在后续的测试中,竟然存在部分设备返回 currentDisplay 中的 id 参数为 “”(空字符串)。
这样,无法通过 display_id 与 id 的一一对应,而确定截取的是哪个屏幕。
为什么会出现这种情况?在 github 上 electron 的代码库中有此讨论。
请看这里 desktopCapturer display_id is empty string

根据讨论,另一种方法为下,

function getCurrentScreen() {
  let currentBounds = win.getBounds();
  let currentDisplay = screen.getDisplayNearestPoint({ x: currentBounds.x, y: currentBounds.y });
  let allDisplays = screen.getAllDisplays();
  let currentDisplayIndex = allDisplays.findIndex((display) => {
    return display.id === currentDisplay.id
  });
  return { 'screen_index': currentDisplayIndex };;
}

那么梳理一下流程:渲染进程响应一个点击事件,向主进程发送一个消息,获取当前屏幕的截屏数据:

// 渲染进程
let data = await this.electron.ipcRenderer.invoke("get-screenshot");

// 主进程
ipcMain.handle('get-screenshot', async (e, args) => {
    let current_screen = getCurrentScreen();  // 取得当前屏幕
    let primaryDisplay = screen.getPrimaryDisplay();
    // 这里的 primaryDisplay.size 由于缩放的原因可能与系统设置的分辨率不一样, 再乘上缩放比 scaleFactor
    let reality_width = primaryDisplay.size.width * primaryDisplay.scaleFactor;
    let reality_height = primaryDisplay.size.height * primaryDisplay.scaleFactor;
    let thumbSize = { width: reality_width, height: reality_height };
    let source = await getDesktopCapturer(current_screen, thumbSize); // 取得当前屏幕截屏数据
    if (source) {
        return source;
    }
});

async function getDesktopCapturer(current_screen, thumbSize) {
  let screenName = current_screen['screen_index'] + 1;
  let screen_names = [];
  screen_names.push('Screen ' + screenName);  // 中文为 `screen_names.push('屏幕 ' + screenName);`
  screen_names.push('Entire Screen');  // 中文为 `screen_names.push('整个屏幕');`
  // 以 thumbSize 屏幕分辨率取得所有屏幕截屏数据,如果 types 设置为 ['screen', 'window'] 同时可以获取各个窗口的截屏数据
  let sources = await desktopCapturer.getSources({ types: ['screen'], thumbnailSize: thumbSize });
  // 如果只有一个屏幕,则 name 为'整个屏幕',如果有两个及以上屏幕,则 name 为 '屏幕 1' 和 '屏幕 2'
  if (sources) {
    for (let source of sources) {
      if (screen_names.indexOf(source.name) != -1) {  // 通过 name 确定屏幕
        return source;
      }
    }
  }
}

渲染进程中取到的截屏数据如下:

{
  name: 'Entire Screen',
  id: 'screen:0:0',
  thumbnail: NativeImage {
    toPNG: [Function: toPNG],
    toJPEG: [Function: toJPEG],
    toBitmap: [Function: toBitmap],
    getBitmap: [Function: getBitmap],
    toDataURL: [Function: toDataURL],
    ...
  },
  display_id: '2528732444',
  appIcon: null
}

thumbnail 为一个对象,通过其中的 toPNG、toJPG、toDataURL 等方法可以将数据转为 PNG、JPG 等格式。
例如以下转为 dataURL,即 base64 编码格式,以便在 web 中显示在 img 标签中:

let data = await this.electron.ipcRenderer.invoke("get-screenshot");
let image_url = data.thumbnail.toDataURL();

又或者在主进程中先转为 PNG 格式 let png_data = data.thumbnail.toPNG();
再使用 fs 模块直接保存到本地 fs.writeFileSync('D:\\1.png', png_data);

在渲染进程中得到了截屏数据,然后就是显示和编辑。

这里选取 ngx-img-cropper 插件。安装 npm i ngx-img-cropper@11.0.0 --save,由于本项目使用 Angular@13.3.1 所以使用 v11.0.0 版本。
ngx-img-cropper 教程。

在 module.ts 中导入 import { ImageCropperModule } from 'ngx-img-cropper';

然后根据教程中 Customizing Image cropper 一节内容这里做如下修改:

home.conponent.html 文件内容如下,去掉多余的选择文件和预览显示,留下编辑部分,再加上三个 button,用于获取截屏,清除截屏,和保存结果。

<div class="container">
  <div style="display: flex;">
    <button (click)="getScreensht()">get</button>
    <button (click)="clear()">clear</button>
    <button (click)="save()">save</button>
  </div>
  <img-cropper #cropper [image]="image_data" [settings]="cropperSettings"></img-cropper>
</div>

home.component.ts 文件修改如下,首先修改 constructor 中的内容,

this.cropperSettings = new CropperSettings();
this.cropperSettings.preserveSize = true;  // 不缩放裁剪图像 以裁剪大小保存
this.cropperSettings.keepAspect = false;  // 不保持裁剪图片纵横比
this.cropperSettings.noFileInput = true;  // 不要 input 标签
this.cropperSettings.cropperDrawSettings.strokeWidth = 2;  // 选择框边框宽度
this.cropperSettings.cropperDrawSettings.strokeColor = '#1296db';  // 选择框边框颜色
this.cropperSettings.cropperDrawSettings.fillColor = '#fff';  // 角选择块颜色
this.cropperSettings.markerSizeMultiplier = 1;  // 角选择块大小
this.cropperSettings.canvasWidth = 960;  // 画布宽
this.cropperSettings.canvasHeight = 540;
this.cropperSettings.width = 960;  // 初始选择框的宽
this.cropperSettings.height = 540;
this.data = { image: '' };

以上配置参数与页面样式或保存图片相关,添加了部分注释,点击 get button 对应的代码如下,首先是向主进程取得数据,转换后赋值。

async getScreensht() {
    let data = await this.electron.ipcRenderer.invoke("get-screenshot");
    let image_url = data.thumbnail.toDataURL();
    this.data['image'] = image_url;
    let image: any = new Image();
    image.src = image_url;
    this.cropper.setImage(image);
}

此时页面如下图显示:

Electron 应用实现截图并编辑功能,Angular,electron,截屏,Angular

这时拖动四个角可以选择截图区域,拖动中间图标可以移动选择截取的区域,点击 clear 清除页面。

clear() {
    this.cropper.reset();
}

点击 save button,则会将图片保存,保存图片方法如下,首先是取得截取的数据,再发送到主进程并重置页面。

save() {
    let base64Data = this.data['image'];
    if (base64Data) {
        this.electron.ipcRenderer.send('save-screenshot', {data: base64Data});
        this.clear();
    }
}

主进程接收到数据后,处理数据,去除 base64 文件编码信息部分,再通过 fs.writeFileSync() 方法保存本地。

ipcMain.on('save-screenshot', (e, args) => {
    let temp_file = "C:\\temp\\test.png"; // 文件路径
    let base64Data = args['data'].replace(/^data:image\/png;base64,/, '');
    let imageBuffer = Buffer.from(base64Data, 'base64');
    fs.writeFileSync(temp_file, imageBuffer);
});

到此即可将截屏数据显示再页面上,编辑后保存到本地。不过 ngx-img-cropper 这个插件的功能较少,暂时只能编辑大小。
CropperSettings 还有一些其他的参数,可以看 ngx-img-cropper 教程,centerTouchRadius 可以设置拖动图标的范围,默认是图标所在区域的一小部分。
一些问题,如果编辑图片的窗口是动态的,则 this.cropperSettings.canvasWidth = 960; 这些设置宽高的参数可以在 ngOnInit() 初始化中取得参数后设置。
当前截图类似与 QQ 聊天窗口中的屏幕截图按钮,会将主窗口一同截取。如果想实现 QQ 截图快捷键的操作(不截取聊天窗口,本项目是主窗口),
一种办法是在通过 desktopCapturer.getSources() 取得屏幕资源数据前最小化(minimize 方法)主窗口。并在资源数据返回到渲染进程时,再显示(show 方法)主窗口。
需要注意,要先判断主窗口最小化,再取数据,因为 minimize 需要等待时间才能获取数据。文章来源地址https://www.toymoban.com/news/detail-647577.html

到了这里,关于Electron 应用实现截图并编辑功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Electron】富文本编辑器之文本粘贴

    由于这个问题导致,从其他地方复制来的内容 粘贴发送之后都会多一个 换行 在发送的时候如果直接,发送innerHTML 就 可以解决 Electron h5 Andriod 都没问题,但是 公司的 IOS 端 不支持,且不提供支持(做不了。)。 于是,继续想办法。 把单纯的富文本插入操作,改一下,只粘

    2024年02月03日
    浏览(44)
  • electron应用重启,开机自启动(electron开发常用的方法、优化方案)

    不会了一定先去参考官网:electron官网 主进程中监听 页面中调用 如果不启用非开发环境的话,开发者电脑开机会出现:To run a local app, execute the following on the command line: 弹框,解决方法就是开发环境不启用开机自启动,代码如上 思路:用nodejs去先定时重启应用,在杀死对应软

    2024年02月12日
    浏览(38)
  • WebOffice在VUE/Electron网页在线编辑Office之用只读方式打开Word文档

    在一些在线 Office 文档中,有很多重要的文件需要保密控制,比如:报价单、客户资料等数据,只能给公司成员查看,但是不能编辑,并且不能拷贝,防止重要资料外泄。可以通过猿大师办公助手的在线 Office 的文档编辑权限来解决这些问题! 第一步:下载安装猿大师办公助

    2024年01月22日
    浏览(67)
  • electron27+react18集成搭建跨平台应用|electron窗口多开

    electron27-vite4-react18基于electron27结合vite4构建工具快速创建react18跨端应用实践。 版本列表 快速创建react18项目 这里选择使用vite.js构建工具来快速创建一个react18项目。 这样一个简单的react18项目就已经创建完毕了。 安装electron依赖包 注意:electron依赖安装在 devDependencies 里面。

    2024年02月08日
    浏览(56)
  • electron 应用全屏

    全屏: ./xxx.AppImage -m https://xiaoman.blog.csdn.net/article/details/131713875?spm=1001.2014.3001.5502 https://blog.csdn.net/qq_41544116/article/details/131884282

    2024年02月15日
    浏览(41)
  • Selenium 测试 Electron 应用

    Electron 介绍 Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript代码代码库并创建 在Windows、macOS和Linux上运行的跨平台应用。 • 有哪些应用 有许多我们常见的桌面应用,比如 postman/apifox、slack、

    2024年01月16日
    浏览(34)
  • Electron桌面应用开发基础

    Electron 是一种基于 Chromium 和 Node.js 的开源框架,可以用于快速构建跨平台的桌面应用程序。与传统的桌面应用程序不同,Electron 应用程序使用 HTML、CSS 和 JavaScript 技术 栈来实现界面设计和业务逻辑,并且具有良好的跨平台性能和扩展性。 跨平台性:Electron 可以在 Windows、M

    2024年02月08日
    浏览(44)
  • electron应用打包成功纪念一下

    electron应用打包成功纪念一下,以前曾经行过后来打包各种报错,现在有空就尝试解决一下 首先安装nvm能够方便切换node版本 顺利安装后你用nvm list查看node列表时会告诉你这个nvm不存在 回到最初版本然后打包看各种错误 还有一种错误是定位到js文件catch后面的{,这时只需要再

    2024年02月10日
    浏览(39)
  • Electron 应用性能优化策略大全

    Electron 以其跨平台、统一开发环境的优势吸引了众多开发者投身于桌面应用的构建之中。然而,由于 Electron 应用本质上是一个结合了 Node.js 和 Chromium 浏览器的应用程序,这也意味着在享受便捷的同时,我们也必须面对潜在的性能挑战,特别是 资源消耗 和 内存管理 等问题。

    2024年04月26日
    浏览(72)
  • electron+vue3全家桶+vite项目搭建【25】使用electron-updater自动更新应用

    demo项目地址 electron-updater官网 我们不可能每次发布新的版本都让用户去手动下载安装最新的包,而是应用可以自动下载新包进行覆盖安装,electron-updater就可以非常方便的实现这个功能 引入依赖 实测用pnpm安装打包运行会有问题,这里还是推荐使用npm管理依赖 配置electron-bui

    2024年02月14日
    浏览(72)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包