使用electron属性实现保存图片并获取图片的磁盘路径

在普通的网页开发中,JavaScript由于安全性的考虑,通常是无法直接获取到客户端的磁盘路径的。浏览器出于隐私和安全原因对此类信息进行了限制。

在浏览器环境下,JavaScript主要通过Web APIs来与浏览器进行交互,而这些API通常受到浏览器的安全策略的限制。文件系统信息是被认为是敏感的信息,因此浏览器不提供直接访问客户端磁盘路径的API。所以要使用electron属性来获取。

第一步:

electron分为主进程和渲染进程,主进程就是使用electron的特性属性api,渲染进程就是我们的代码,比如vue页面代码这种。

首先我们要把项目用electron启动起来,具体怎么启动看我上一篇博客

启动完成后,找到项目文件中的backgroun.js文件,这是electron主进程的文件

把以下代码加进去

import { app, protocol, BrowserWindow ,ipcMain,ipcRenderer,dialog} from 'electron'
const fs = require('fs');
app.on('ready', async () => {
  // if (isDevelopment && !process.env.IS_TEST) {
  //   // Install Vue Devtools
  //   try {
  //     await installExtension(VUEJS_DEVTOOLS)
  //   } catch (e) {
  //     console.error('Vue Devtools failed to install:', e.toString())
  //   }
  // }
  createWindow()
  // 新增:在主进程中处理打开保存图片对话框的请求
  ipcMain.handle('dialog:saveImage', async (event, dataURL) => {
    return saveImage(dataURL);
  });
})



// 将保存图片的逻辑封装成一个函数
async function saveImage(dataURL) {
  let base64 = dataURL.replace(/^data:image\/\w+;base64,/, '');
  let dataBuffer = Buffer.from(base64, 'base64');
  const options = {
    title: 'Save Image',
    buttonLabel: '保存', // 自定义保存按钮的文字
    defaultPath: 'image.jpg', // 默认文件名
    filters: [
      { name: 'Images', extensions: ['jpg', 'png', 'gif'] }
    ]
  };
  const { canceled, filePath } = await dialog.showSaveDialog(options);
  if (canceled) {
    return null; // 用户取消保存文件时返回 null
  } else {
    // 将 dataURL 保存到 filePath 的逻辑代码
    fs.writeFile(filePath, dataBuffer, function (err) {
      if (err) {
        console.error(err, '保存失败');
      } else {
        console.log(filePath, '保存成功');
      }
    });
    return filePath; // 返回用户选择的文件路径
  }
}
  1. 在 Electron 应用程序启动后,创建了窗口(createWindow函数应该是在代码中其他位置定义的)。
  2. 通过 ipcMain.handle 方法,为名为 'dialog:saveImage' 的事件注册了一个处理函数,用于处理保存图片对话框的请求。当渲染进程发送 'dialog:saveImage' 事件时,主进程将会执行 saveImage 函数。
  3. saveImage 函数封装了保存图片的逻辑。首先将 Data URL 转换为 Buffer 格式,然后通过 dialog.showSaveDialog 方法展示保存对话框,用户选择保存路径后,将图片文件保存到指定路径。
  4. saveImage 函数中:

  5. 首先通过 dataURL.replace 和 Buffer.from 将 Data URL 转换成了 Buffer 格式。
  6. 然后使用 dialog.showSaveDialog 方法展示保存对话框,用户选择保存路径后,通过 fs.writeFile 方法将 Buffer 写入文件。
  7. 最后根据保存成功或失败,返回相应的结果给渲染进程。

fs 是 Node.js 核心模块中的一个模块,全称为 File System(文件系统)。这个模块提供了一系列用于处理文件和文件系统的方法,可以用于读取文件、写入文件、创建目录、删除文件等操作。通过 fs 模块,你可以在 Node.js 程序中对文件和文件系统进行各种操作,包括读写文件、文件夹的操作等。

在 Electron 应用程序中,由于可以利用 Node.js 的能力,因此可以在主进程中使用 fs 模块来处理文件和文件系统相关的操作,比如在上面的代码中就使用了 fs.writeFile 方法来将图片保存到指定路径。

这是最终background.js文件的代码:

'use strict'

import { app, protocol, BrowserWindow ,ipcMain,ipcRenderer,dialog} from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
// import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
const fs = require('fs');

// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
  { scheme: 'app', privileges: { secure: true, standard: true } }
])

async function createWindow() {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      
      // Use pluginOptions.nodeIntegration, leave this alone
      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
      contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION
    }
  })

  win.maximize()

  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
  }
}

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (BrowserWindow.getAllWindows().length === 0) createWindow()
})

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
  // if (isDevelopment && !process.env.IS_TEST) {
  //   // Install Vue Devtools
  //   try {
  //     await installExtension(VUEJS_DEVTOOLS)
  //   } catch (e) {
  //     console.error('Vue Devtools failed to install:', e.toString())
  //   }
  // }
  createWindow()
  // 新增:在主进程中处理打开保存图片对话框的请求
  ipcMain.handle('dialog:saveImage', async (event, dataURL) => {
    return saveImage(dataURL);
  });
})

// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
  if (process.platform === 'win32') {
    process.on('message', (data) => {
      if (data === 'graceful-exit') {
        app.quit()
      }
    })
  } else {
    process.on('SIGTERM', () => {
      app.quit()
    })
  }
}


// 将保存图片的逻辑封装成一个函数
async function saveImage(dataURL) {
  let base64 = dataURL.replace(/^data:image\/\w+;base64,/, '');
  let dataBuffer = Buffer.from(base64, 'base64');
  const options = {
    title: 'Save Image',
    buttonLabel: '保存', // 自定义保存按钮的文字
    defaultPath: 'image.jpg', // 默认文件名
    filters: [
      { name: 'Images', extensions: ['jpg', 'png', 'gif'] }
    ]
  };
  const { canceled, filePath } = await dialog.showSaveDialog(options);
  if (canceled) {
    return null; // 用户取消保存文件时返回 null
  } else {
    // 将 dataURL 保存到 filePath 的逻辑代码
    fs.writeFile(filePath, dataBuffer, function (err) {
      if (err) {
        console.error(err, '保存失败');
      } else {
        console.log(filePath, '保存成功');
      }
    });
    return filePath; // 返回用户选择的文件路径
  }
}

第二步:

去渲染进程里写相关代码,也就是你的.vue文件

   //保存画布图片
    saveCanvasBackground() {
      if (this.image.url == '') return
      // 获取 canvas 元素和 Fabric 对象
      const canvas = document.getElementById("label-canvas");
      const fabricObj = this.fabricObj;
      // 将 canvas 内容保存为图片数据 URL
      const dataURL = canvas.toDataURL({
        format: "png", // 保存的图片格式
        quality: 0.8, // 图片质量
      });


      //想主进程发送打开保存图片选项框请求
      ipcRenderer.invoke('dialog:saveImage', dataURL).then(response => {
        console.log(response, 'sssss');
        if (response) {
          // 接口
          // setsaveImage({
          //   img:response
          // }).then(res=>{
          //   console.log(res,'保存成功接口');
          // }).catch(err=>{
          //   console.log(err,'保存失败接口');
          // })
        } else {
          //用户取消
        }
      }).catch(err => {
        console.error(err);
      });

      // 创建一个 Blob 对象
      // const byteCharacters = atob(dataURL.split(",")[1]);
      // const byteNumbers = new Array(byteCharacters.length);
      // for (let i = 0; i < byteCharacters.length; i++) {
      //   byteNumbers[i] = byteCharacters.charCodeAt(i);
      // }
      // const byteArray = new Uint8Array(byteNumbers);
      // const blob = new Blob([byteArray], { type: "image/png" });
      // // 创建一个下载链接
      // const url = URL.createObjectURL(blob);
      // // 创建一个下载按钮并触发点击
      // const a = document.createElement("a");
      // a.style.display = "none";
      // a.href = url;
      // a.download = "saved_image.png"; // 设置下载的文件名
      // document.body.appendChild(a);
      // a.click();
      // // 释放对象 URL,避免内存泄漏
      // window.URL.revokeObjectURL(url);
    },

这段代码是在渲染进程中使用 ipcRenderer.invoke 方法向主进程发送了一个名为 'dialog:saveImage' 的请求,同时传递了一个名为 dataURL 的参数。当主进程处理完这个请求后,渲染进程会接收到相应的结果。

在这段代码中,使用了 ipcRenderer.invoke 方法来发送请求,并通过 Promise 对象处理响应。如果主进程成功处理了请求并返回了结果,会执行 then 中的代码,如果出现错误,会执行 catch 中的代码。

then 中的代码中,首先会打印出返回的 response,然后根据返回的结果进行相应的处理。如果 response 存在,表示图片保存成功,可以处理接口请求或其他逻辑;如果 response 不存在,表示用户取消了保存操作,可以做出相应的反应。

整体来说,这段代码的作用是在渲染进程中向主进程发送保存图片选项框的请求,并根据主进程返回的结果进行相应的处理。

以上红色框内就是运行过后获取出来当前保存图片的磁盘路径!

双击点赞!!!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/277219.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

lottie 动画在 vue 中的使用

前言 最近我所负责的项目中采用了动画效果&#xff0c;最早使用 gif 来实现。然而&#xff0c;在实践过程中&#xff0c;我发现 gif 格式的动画在 git 中出现了明显的锯齿感&#xff0c;这让我非常困扰。为了追求更完美的表现效果&#xff0c;我最终选择了 lottie 来实现我的动…

C++核心编程四(继承、多态、virtual关键字、文件操作)

文章目录 继承继承方式继承中的对象模型继承中构造和析构顺序继承同名成员处理方式继承同名<静态>成员处理方式多继承语法菱形继承多态多态案例1、计算器类 纯虚函数和抽象类多态案例2、制作饮品 虚析构和纯虚析构多态案例3、电脑组装 文件写操作读文件二进制写文件二进制…

ClickHouse基础知识(四):ClickHouse 引擎详解

1. 表引擎的使用 表引擎是 ClickHouse 的一大特色。可以说&#xff0c; 表引擎决定了如何存储表的数据。包括&#xff1a; ➢ 数据的存储方式和位置&#xff0c;写到哪里以及从哪里读取数据。 默认存放在/var/lib/clickhouse/data ➢ 支持哪些查询以及如何支持。 ➢ 并发数…

CUDA驱动深度学习发展 - 技术全解与实战

全面介绍CUDA与pytorch cuda实战 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0c;复旦机器人智能实验室成员&#xff0c;阿里云认证的资深架构师&#xff0c;项目管理专业人士&…

【SD】保持图片大小 精细化处理 高清放大

首先开启 ADetailer可以修复手部&#xff0c;脸部&#xff0c;全身。 生成一张图片。 best quality,masterpiece,simple_white_background,golden and white theme,Sense of coordination,sense of order,mathematics beauty,(((cover design))),(((((cover art))))),((trim)),…

喜讯!云起无垠获评ISC 2023数字安全创新能力百强双料大奖

近日&#xff0c;第四届数字安全“奥斯卡”——ISC 2023数字安全创新能力百强评选活动在北京圆满闭幕。本次活动旨在挖掘和孵化数字安全领域的“专精特新”力量&#xff0c;共同推进数字中国的安全建设。 在本次评选中&#xff0c;云起无垠凭借其在软件供应链安全领域的创新实…

SpringBoot 3.2.0 结合Redisson接入Redis

依赖版本 JDK 17 Spring Boot 3.2.0 Redisson 3.25.0 工程源码&#xff1a;Gitee 集成Redis步骤 导入依赖 <properties><redisson.version>3.25.0</redisson.version> </properties> <dependencies><dependency><groupId>org.pr…

Vue3-30-路由-嵌套路由的基本使用

什么是嵌套路由 嵌套路由 &#xff1a;就是一个组件内部还希望展示其他的组件&#xff0c;使用嵌套的方式实现页面组件的渲染。 就像 根组件 通过路由渲染 普通组件一样&#xff0c;嵌套路由也是一样的道理。 嵌套路由的相关关键配置 1、<router-view> 标签 声明 被嵌套组…

Echarts中饼图-实现放大显示数据

示例 代码演示 option {tooltip: {trigger: item},legend: {top: 5%,left: center},series: [{name: Access From,type: pie,radius: [40%, 70%],avoidLabelOverlap: false,label: {show: false,position: center},emphasis: {scale: true,//是否开启高亮后扇区的放大效果。s…

python查找mongo中符合条件的json记录

一、需求&#xff1a; 之前有次需要临时查找mongo中存储的json串&#xff0c;符合特定条件的记录&#xff1b; 举个例子&#xff0c;mongo中记录如下图&#xff1a; 其中每条存储的数据大概为&#xff1a; [{"createUser": "Zxtech","paramName&qu…

LVM逻辑卷与扩容

目录 一.LVM&#xff1a; 1.什么是LVM&#xff1a; 2.LVM的基本核心组件&#xff1a; 3.LVM的基本命令&#xff1a; 二.逻辑卷的创建&#xff1a; 第一步&#xff0c;我们先要为虚拟机添加硬盘 然后我们要添加依赖包 然后我们要进行磁盘分区 再添加好分区后&#xff0…

回顾2023,展望2024

时光飞逝&#xff0c;光阴似箭&#xff0c;转眼间又到了一年的年末&#xff0c;现在是2023年12月29日&#xff0c;再过两天就要元旦了&#xff0c;我们也要跨入2024年了。 记录自己的总结&#xff0c;一直想写&#xff0c;不知从何写起&#xff0c;在这一年中&#xff0c;有深夜…

程序员实现财富自由的十种方法!

程序员肯定都有过一夜暴富的梦想&#xff0c;也许是兼职接单&#xff0c;也许是成为炙手可热的大网红&#xff0c;也许只是平凡的中张百万大奖彩票…… 除去运气超好实力拔群以外&#xff0c;大多数程序员是很难在短时间内实现财富自由的。虽是如此&#xff0c;但搞钱对于程序…

Unity Shader-真实下雨路面

Unity Shader-真实下雨路面 简介素材1.准备插件Amplify Shader Editor&#xff08;这里我使用的是1.6.4最新版&#xff09;2.贴纸和切图d 一、创建一个Shader Surface&#xff0c;实现气泡播放效果二、叠加一次气泡播放效果&#xff0c;使其看起来更多&#xff0c;更无序三、小…

Matplotlib_plt.subplots 遇见中文乱码解决方案

文章目录 一、现象&#xff1a;二、解决方案1.将 **SimHei.ttf** &#xff0c;下载到当前运行目录中2.绘图中涉及标题、横纵坐标等&#xff0c;加上 **FontProperties font** 即可 环境说明&#xff1a;macOS系统 一、现象&#xff1a; 原先代码是这样的 import numpy as n…

BUUCTF Reverse/[2019红帽杯]Snake

BUUCTF Reverse/[2019红帽杯]Snake 下载解压缩后得到可执行文件&#xff0c;而且有一个unity的应用程序&#xff0c;应该是用unity编写的游戏 打开是一个贪吃蛇游戏 用.NET Reflector打开Assembly-CSharp.dll。&#xff08;unity在打包后&#xff0c;会将所有的代码打进一个Ass…

二、类与对象(三)

17 初始化列表 17.1 初始化列表的引入 之前我们给成员进行初始化时&#xff0c;采用的是下面的这种方式&#xff1a; class Date { public:Date(int year, int month, int day)//构造函数{_year year;_month month;_day day;} private:int _year;int _month;int _day; };…

社招面试题:说一说SPI是什么,有哪些使用场景?

大家好&#xff0c;我是小米&#xff01;今天在这里和大家分享一个在技术面试中常被问到的话题——SPI&#xff08;Service Provider Interface&#xff09;&#xff0c;这是一个令人着迷的技术领域&#xff0c;也是很多Java开发者必须要熟悉的概念。不废话&#xff0c;让我们一…

TikTok短视频互动:设计引人入胜的玩法体验

在数字社交的浪潮中&#xff0c;TikTok以其独特的短视频形式和丰富多彩的互动玩法&#xff0c;成为了全球年轻一代热衷的社交平台。本文将深入剖析TikTok短视频互动的精髓&#xff0c;探讨其设计背后的原理&#xff0c;以及为何这种互动体验如此吸引人。 创意挑战的魅力 TikTok…

机器视觉在智能交通与无人驾驶领域的应用及前景

​引言 机器视觉算法对于智能交通系统和无人驾驶技术是十分重要的。机器视觉技术是无人驾驶汽车感知环境、做出决策的关键&#xff0c;它使得车辆能够理解周围的世界并安全地导航。在智能交通系统中&#xff0c;机器视觉也发挥着至关重要的作用&#xff0c;从提高交通效率到增…