5、终篇:图片下载,设置为桌面壁纸

142 阅读1分钟

图片下载,设置为桌面壁纸

1、提供两种图片下载功能

  1. 通过网络地址下载。
  2. 图片已经加载成功,直接实现另存为,无需再次通过网络请求下载(该软件采用此下载方式,当然方式一也可以)。

方式一

这个下载和前文的软件下载基本一致,不再做过多叙述,需要可前往 juejin.cn/post/744124… 查看。

// 文件下载 currentWindow 当前窗口
export const downloadFileToFolder = (currentWindow: BrowserWindow, downloadUrl: string, fileName: string, savePath: string) => {
    const targetFolder = path.join(savePath)

    // 如果目标文件夹不存在,则创建它
    if (!fs.existsSync(targetFolder)) {
        fs.mkdirSync(targetFolder, { recursive: true })
    }

    const fullFileName = `${fileName}.png`
    const filePath = path.join(targetFolder, fullFileName)
    const stream = fs.createWriteStream(filePath)

    let totalBytes = 0
    let downloadedBytes = 0

    axios({
        method: 'GET',
        url: downloadUrl,
        responseType: 'stream'
    }).then((response) => {
        totalBytes = parseInt(response.headers['content-length'], 10)

        response.data.on('data', (chunk) => {
            downloadedBytes += chunk.length
            // 计算下载进度百分比
            const progress = Math.floor((downloadedBytes / totalBytes) * 100)
            // 只将进度信息发送给当前发起下载请求的窗口的渲染进程
            if (currentWindow) {
                currentWindow.webContents.send('download-progress', progress)
            }
        })

        response.data.pipe(stream)

        return new Promise((resolve, reject) => {
            stream.on('close', () => {
                // 通知渲染进程下载成功
                if (currentWindow) {
                    const obj = {
                        type: 'success',
                        message: '下载成功'
                    }
                    currentWindow.webContents.send('download-complete', obj)
                    resolve(true)
                }
                // 通知渲染进程下载成功 (所有窗口)
                // BrowserWindow.getAllWindows().forEach((window) => {
                //     const obj = {
                //         type: 'success',
                //         message: '下载成功'
                //     }
                //     window.webContents.send('download-complete', obj)
                //     resolve(true)
                // })
            })

            stream.on('error', (err) => {
                stream.close()
                // 通知渲染进程下载失败
                if (currentWindow) {
                    const obj = {
                        type: 'error',
                        message: '下载失败'
                    }
                    currentWindow.webContents.send('download-complete', obj)
                    reject(err)
                }
            })
        })
    }).catch((_) => {
        stream.close()
        // 通知渲染进程下载失败
        if (currentWindow) {
            const obj = {
                type: 'error',
                message: '下载失败'
            }
            currentWindow.webContents.send('download-complete', obj)
        }
    })
}

方式二

  • 主要介绍该方法,主要思路,通过把图片重新绘制在 canvas 画布上,在提取图片实现另存为。
  • 设置 canvas 宽高时使用原始尺寸,而非展示尺寸。
  • 建议使用jpg压缩格式,png压缩格式会出现图片过大,影响后续设置壁纸功能,win11大概是超过35M就无法设置壁纸了。
<template>
     ···
       <img v-show="successLoading && !loadingError" :src="downs[showImgIndex].src" class="elImg" alt=""
            @click="viewImg(downs[showImgIndex].src)" @load="imgLoadEvent" @error="imgErrorEvent" />
     ···
</template>

<script setup lang="ts">
···
let myApi
···
const downloadTheOriginalImage = (setWallpaper: boolean = false) => {
    const elImg = document.querySelector('.elImg') as HTMLImageElement
    // 创建一个隐藏的canvas元素
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')!
    // 设置canvas的尺寸与图片原始尺寸一致
    canvas.width = elImg.naturalWidth
    canvas.height = elImg.naturalHeight
    // 将图片绘制到canvas上
    ctx.drawImage(elImg, 0, 0, elImg.naturalWidth, elImg.naturalHeight)
    // 异步保存图片 避免主线程阻塞
    setTimeout(() => {
        // 获取canvas的Base64编码数据,指定格式为jpg
        const base64Data = canvas.toDataURL(imgFormat.value)
        // 从Base64数据中提取图片格式信息
        const imageFormat = imgFormat.value == 'image/png' ? 'png' : 'jpg'
        // 后续可以根据提取出的图片格式和保存路径等信息进行保存图片等操作
        // 例如,以下是简单示意如何拼接正确的文件名用于保存(假设已经导入了path模块)
        const fs = require('fs')
        const path = require('path')
        if (!fs.existsSync(downloadLocation.value)) {
            try {
                fs.mkdirSync(downloadLocation.value);
            } catch (err) {
                ElMessage({
                    message: '创建下载文件夹失败:' + err,
                    type: 'error',
                    plain: true,
                })
                return
            }
        }
        const name = setWallpaper == true ? 'desktopWallpaper' : Date.now()
        const fileName = `${name}.${imageFormat}`
        const fullPath = path.join(downloadLocation.value, fileName)
        fs.writeFile(fullPath, Buffer.from(base64Data.replace(/^data:image\/\w+;base64,/, ''), 'base64'), async (err) => {
            if (err) {
                ElMessage({
                    message: '保存失败' + err,
                    type: 'error',
                    plain: true,
                })
            } else {
                // 这里是设置壁纸功能
                if (setWallpaper == true) {
                    const obj = { path: fullPath }
                    await myApi.setWallpaper(obj)
                    ElMessage({
                        message: '设置成功',
                        type: 'success',
                        plain: true,
                    })
                } else {
                    ElMessage({
                        message: '保存成功',
                        type: 'success',
                        plain: true,
                    })
                }
            }
        })
    }, 0)
}
···

onMounted(() => {
    myApi = window.api as any
    ···
})
onBeforeUnmount(() => {
    ···
})
</script>

2、设置壁纸功能

  • 使用的插件 wallpaper
  • 注意事项:electron-vite 不支持 wallpaper 最新版本的导入方式,虽然可以使用动态导入的方式导入,但是打包的时候还是会出问题,没能解决动态打包问题,因此我采用了 5.0.1 版本实现的,大佬可自行选择。
  • 用法非常简单,导入函数,传入图片路径即可。
  • 然后就是在主进程注册消息,预加载挂载,渲染进程调用一系列操作就不再做过多叙述。
  • 至此,一些基本功能已经全部介绍完毕,一些简单功能懒得写了,代码里面都有。
import wallpaper from 'wallpaper'
// 设置本地图片为壁纸
export const setPictureAsWallpaper = async (Path: string) => {
    try {
        await wallpaper.set(Path)
    } catch (err) {
        console.error('加载wallpaper模块或设置壁纸失败:', err)
    }
}