Electron中如何读取本地图片到Canvas并获取图片尺寸?
我正在开发一款Electron应用,允许用户选择本地磁盘中的图片。我需要读取图片内容并将其显示在Canvas中用于编辑,为此需要完成两项任务:
- 读取图片内容并显示到Canvas上
- 获取图片的原始尺寸
为完成第一项任务,我使用fs.readFileSync读取文件内容:
let imageData = fs.readFileSync(pathToFile);加载PNG图片时,这会返回一个Uint8Array。为将其放入Canvas,我尝试创建ImageData对象(该对象需要Uint8ClampedArray类型),于是进行了如下转换:
let array = new Uint8ClampedArray(this.imageBuffer); let imageData = new ImageData(array, canvas.width, canvas.height); // Error ctx.putImageData(imageData, 0, 0);然而,虽然文件加载正常,但将其显示到Canvas时出现错误:
"Failed to construct 'ImageData': The input data length is not a multiple of 4."我推测直接读取的PNG数据格式不符合ImageData的要求,请问如何正确格式化这些数据?以及如何通过这些数据获取图片的原始尺寸?
你直接用fs.readFileSync读出来的是PNG的压缩二进制数据,不是Canvas需要的像素原始数据(RGBA格式,每个像素4字节),所以直接转成Uint8ClampedArray会报错,因为数据长度和像素点数量不匹配。下面是正确的实现方式:
一、正确将图片显示到Canvas
不要直接处理文件二进制,而是用浏览器原生的Image对象加载图片,Electron渲染进程完全支持这个API:
const fs = require('fs'); // 假设已通过文件选择框拿到图片路径pathToFile const img = new Image(); // 将本地图片转成base64格式加载 img.src = `data:image/png;base64,${fs.readFileSync(pathToFile).toString('base64')}`; img.onload = () => { const canvas = document.getElementById('your-canvas-id'); const ctx = canvas.getContext('2d'); // 把Canvas尺寸设为图片原始尺寸 canvas.width = img.width; canvas.height = img.height; // 绘制图片到Canvas ctx.drawImage(img, 0, 0); // 如果需要编辑像素,现在可以获取ImageData const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); }; img.onerror = (err) => { console.error('图片加载失败:', err); };
如果是通过<input type="file">获取的文件对象,用URL.createObjectURL更高效:
// 假设通过文件选择框拿到了file对象 const img = new Image(); img.src = URL.createObjectURL(file); img.onload = () => { // 同上绘制逻辑 URL.revokeObjectURL(img.src); // 及时释放资源 };
二、获取图片原始尺寸
在img.onload回调中,img.width和img.height就是图片的原始尺寸,无需额外解析二进制。
如果一定要直接解析PNG二进制数据获取尺寸(比如不想加载图片),可以读取PNG文件头部的固定位置数据:
const buffer = fs.readFileSync(pathToFile); // PNG文件的宽度在第16-19字节,高度在20-23字节,均为大端序 const width = buffer.readUInt32BE(16); const height = buffer.readUInt32BE(20); console.log('原始尺寸:', width, height);
错误原因说明
ImageData要求的是每个像素4字节(RGBA)的原始像素数据,而fs.readFileSync读取的是包含文件头、压缩块的PNG格式数据,长度必然不是4*宽*高的倍数,因此构造ImageData时会报错。必须先让浏览器解析图片,得到原始像素数据后再处理。
内容的提问来源于stack exchange,提问作者MWinstead

