image-size 是什么
一个Node模块,用于获取任何图像文件的尺寸。
git:https://github.com/image-size/image-size
源码解析
首先整理出一份流程图来分析 一图胜万语:
吸取到的营养
-
nodejs 的包加载机制
bin/image-size.js
var imageSize = require('..'); 复制代码
package.json
"main": "lib/index.js" 复制代码
require('..') 具体加载了哪个文件?
nodejs 的包加载机制会把 '..' 解析成 '../',然后会尝试去 package.json 内取 main 字段的值,作为文件加载的入口,所以这里加载了 lib/index.js。
-
检测用户的输入
var files = process.argv.slice(2); if (!files.length) { console.error('Usage: image-size image1 [image2] [image3] ...'); process.exit(-1); } 复制代码
通过 process.argv.slice(2) 获取用户的输入,并且在用户没有输入的情况下给予提示和帮助。
-
检测当前文件是否存在
fs.existsSync(path.resolve(image) 复制代码
先把图片的路径转换为绝对路径 然后调用 fs.existsSync 方法。
虽然 fs.exists() 是废弃的,但 fs.existsSync() 不是。--nodejs 文档
-
读取文件转换为 buffer
- 异步转换
function asyncFileToBuffer (filepath, callback) { // open the file in read only mode fs.open(filepath, 'r', function (err, descriptor) { if (err) { return callback(err); } fs.fstat(descriptor, function (err, stats) { if (err) { return callback(err); } var size = stats.size; if (size <= 0) { return callback(new Error('File size is not greater than 0 —— ' + filepath)); } var bufferSize = Math.min(size, MaxBufferSize); var buffer = new Buffer(bufferSize); // read first buffer block from the file, asynchronously fs.read(descriptor, buffer, 0, bufferSize, 0, function (err) { if (err) { return callback(err); } // close the file, we are done fs.close(descriptor, function (err) { callback(err, buffer); }); }); }); }); } 复制代码
- 同步转换
function syncFileToBuffer (filepath) { // read from the file, synchronously var descriptor = fs.openSync(filepath, 'r'); var size = fs.fstatSync(descriptor).size; var bufferSize = Math.min(size, MaxBufferSize); var buffer = new Buffer(bufferSize); fs.readSync(descriptor, buffer, 0, bufferSize, 0); fs.closeSync(descriptor); return buffer; } 复制代码
- 先打开文件 fs.open
- 获取文件信息 fs.fstat
- 满足条件的话,读取文件 fs.read
- 成功后,关闭文件流 fs.close
这里作者限制了 buffer 的大小,不然的话使用 fs.createReadStream 更为方便些。
-
检测图片的类型
-
在 lib/types 文件夹内有着所有格式的扩展类,并且在 lib/types.js 文件内统一加载导入
var typeHandlers = { bmp: require('./types/bmp'), cur: require('./types/cur'), dds: require('./types/dds'), gif: require('./types/gif'), icns: require('./types/icns'), ico: require('./types/ico'), jpg: require('./types/jpg'), png: require('./types/png'), psd: require('./types/psd'), svg: require('./types/svg'), tiff: require('./types/tiff'), webp: require('./types/webp'), }; 复制代码
可以用一个类专门做多文件导入之类的处理。
-
所有的格式扩展类导出的方法名都是 'detect' 和 'calculate'
lib/detector.js
module.exports = function (buffer, filepath) { var type, result; for (type in typeHandlers) { result = typeHandlers[type].detect(buffer, filepath); if (result) { return type; } } }; 复制代码
统一了格式扩展类导出的方法名,方便扩展。以后再扩展不同格式的图片时,只需要增加对应的格式扩展类,而无需改变当前的代码。(对修改关闭 对扩展开放 --ocp原则)
-
-
获取图片的信息
不同的图片格式获取信息的方式不一致,这里涉及的知识有点深,这里只是记录下思路,具体需要时在详细的查询。
- 基于 buffer 读取字节,基于格式说明,读取出相对应的二进制数据信息。
记录大端读取和小端读取的区别:
const buf = Buffer.from([0x12, 0x34, 0x56]); console.log(buf.readUInt16BE(0).toString(16)); // Prints: 1234 大端在右 console.log(buf.readUInt16LE(0).toString(16)); // Prints: 3412 小端在右 复制代码
-
console.log 输出带颜色的字体
在最后返回结果的时候,宽和高数据都是绿色的。发现 console.log 原来是可以设置 css 样式的。
例如(可以在 chrome 开发者模式下输入看下样式)
console.log( '%c你好', 'color:red' ) 复制代码
%c 后面的所有字体可以作用写好的 css样式。
console.log( '%c你好%c今天学习了吗', 'color:red' , 'color:yellow') 复制代码
多个字体样式的使用
总结
阅读源码可以开阔自己的视野,也能更好的学习 nodejs。先从简单的模块入手,慢慢在增加难度,学习作者的思路和套路。