1. 文件转 Base64

在大规模使用 FileSystem接口之前,前端读取文件主要靠 input[type='file'] 元素。开发者通常会随手创建一个 FileReader 实例来读取文件,用完之后随即抛弃之,不得不说真是无情。实际上这个实例是可以复用起来的:

/**
* @method blob2Base64 - 将 blob 文件转为 Base64 URL
* @returns {Promise<String>}
* */
const blob2Base64 = (() => {
const fileReader = new FileReader();
let resolver = null, errHandler = null;
fileReader.onload = () => resolver(fileReader.result);
fileReader.onerror = err => errHandler(err);

return file => {
fileReader.readAsDataURL(file);
return new Promise((resolve, reject) => {
resolver = resolve;
errHandler = reject;
})
}
})();


这种代码最常用于读取用户选取的图片,使用的时候:

const readFileFromInput = async event => {
const { target: { files: [file] }} = event;
const base64 = await blob2Base64(file);
console.log('read data as base64:', base64);
}
document.querySelector('input[type="file"]').addEventListener('change', readFileFromInput);


 

2. 从URL加载图片

前端处理图片通常依赖于 canvas ,而 canvas 绘图上下文不支持直接从 URL 读取图片,所以我们需要创建一个图片对象,并在其加载完成后再绘制到 canvas 上,鉴于 canvas 会将图片数据复制一份,这个图片对象是可以复用的:

/**
* @const loadImageFromURL - 从 URL 加载图片
* */
const loadImageFromURL = (() => {
const image = new Image();
image.setAttribute('crossOrigin', 'Anonymous');
let resolver = null, errHandler = null;
image.onload = () => {
resolver(image);
};
image.onerror = err => {
errHandler(err);
};
return URL => {
return new Promise((resolve, reject) => {
resolver = resolve;
errHandler = reject;
image.src = URL;
});
}
})();


当然,如果是使用 Knova 这样的绘图库的话,每添加一张图片都需要创建新的 Image 对象,这段代码稍加修改就可以胜任了。

 

3. 获取图片BitMap数据

借助 canvas 我们可以将浏览器支持的所有格式的图片解码得到其位图数据,不过,这个需求并不常见,除非你想亲手实现一下二维码扫描功能。这里需要复用的,是一个 canvas 元素对象及其绘图上下文:

/**
* @method imageFileToImageData - 读取图片文件的为位图数据
* @param {File} blob - 需要转换的文件对象
* @return {Promise<ImageData>}
*/const imageFileToImageData = (() => {
const canvas = document.createElement('canvas');
canvas.setAttribute('crossOrigin', 'Anonymous');
const context = canvas.getContext('2d');
return async blob => {
const image = await loadImageFromURL(await blob2Base64(blob));
const { width, height } = image;
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
context.drawImage(image, 0, 0, width, height);
return context.getImageData(0, 0, width, height);
};
})();


上面的两个方法在这里都已经用上了,可以看出简直是简洁、方便、清晰到家了!

4. 文件下载

文件下载的原理是借助一个 a[download] 元素触发点击事件,同样地,这个元素也是可以复用的:

/**
* 传入 URL 下载文件
* */
const downLoadPicByURL = (() => {
const anchor = document.createElement('a');
return (URL, filename = 'download') => {
anchor.setAttribute('href', URL);
anchor.setAttribute('download', filename);
anchor.click();
}
})();


当然,由于下载的过程没法监听更没法控制,这个方法不返回任何有效信息。