1

代码只在window下可用

直接上代码:
代码摘抄过程中可能有遗漏或错误,欢迎指出

electron: "25.2.0",低于此版本的 protocol 写法不同,请自行处理

需要的npm包:

npm install gm

需要的第三方开源软件:
GraphicsMagick
extracticon.exe

GraphicsMagick 的效率不错,70MB|4961 × 7016 × 32 BPP的png图片生成300px左右的缩略图耗时大约2s
extracticon 可以提取exe图标里最大的那个为png图片,所以图片大小不一定统一,最大尺寸为 256×256,最小 16×16

img_load:

const spawn = require("child_process").spawn
const os = require("os")
const path = require("path")
const fs = require("fs")

// 我安装GraphicsMagick后无法直接调用,但控制台可以,理由不知道,这里就直接指定程序路径
const gm = require("gm").subClass({
    appPath: "d:/GraphicsMagick/App/",
})

const tempDir = os.tmpdir()

const exeRoot = process.cwd()
console.log(tempDir, exeRoot)

function isExists(filepath) {
    try {
        fs.accessSync(filepath, fs.constants.F_OK | fs.constants.R_OK)
        return true
    } catch (error) {
        return false
    }
}

function getExtracticonPath() {
    // 我放在了根目录下的utils文件夹里
    const p = path.join(exeRoot, "/utils/Image/extracticon.exe")
    console.log(p)
    if (isExists(p)) {
        return p
    }
    return ""
}

export function getIcon(filepath) {
    filepath = decodeURIComponent(filepath)
    return new Promise((resolve, reject) => {
        if (!isExists(filepath)) {
            reject("file not found!")
        }
        const pngname = path.parse(filepath).name + ".png"
        const pngpath = path.join(tempDir, pngname)
        if (isExists(pngpath)) {
            resolve(gm(pngpath).stream("png"))
        }
        const extracticon = getExtracticonPath()
        if (extracticon == "") {
            reject("extracticon.exe not found!")
        }
        const child = spawn(extracticon, [filepath, pngpath])
        child.on("close", (code) => {
            if (code == 0) {
                resolve(gm(pngpath).stream("png"))
            }
            reject("error")
        })
    })
}

export function getThumbnail(filepath, width = 240, height = 400, option = ">") {
    filepath = decodeURIComponent(filepath)
    if (!isExists(filepath)) {
        throw new Error("file not found!")
    }
    return gm(filepath).thumbnail(width, height, option).stream("png")
}

electron:

import { getIcon, getThumbnail } from "./img_load"

app.whenReady().then(()=>{

// 404的返回可以根据需要自行修改
// limg与后面的exei都是可以自定义的

protocol.handle("limg", (request) => {
        let url = request.url.slice("limg:///".length)
        // 这个是node的方式,但支持的格式太少,记得就只有png和jpg,好处是不用第三方软件
        // const image = await nativeImage.createThumbnailFromPath(url, {
        //     width: 240,
        //     height: 100,
        // })
        try {
            let imageBuffer = getThumbnail(url)
            return new Response(imageBuffer, {
                headers: { "content-type": "image/png" },
            })
        } catch (error) {
            console.log(error);
            return new Response("", {
                status: 404,
                headers: { "content-type": "image/png" },
            })
        }
    })

    protocol.handle("exei", async (request) => {
        let url = request.url.slice("exei:///".length)
        try {
            let imageBuffer = await getIcon(url)
            return new Response(imageBuffer, {
                headers: { "content-type": "image/png" },
            })
        } catch (error) {
            console.log(error);
            return new Response("", {
                status: 404,
                headers: { "content-type": "image/png" },
            })
        }
    })
})

vue+pug:

const setAltImg = ({target}) => {
    target.src = "limg:///E:/默认图片.jpg" 
}

img(src="exei:///d:/Software/Ruler.exe", @error="setAltImg")

zeronofreya
192 声望3 粉丝