UNPKG

3.57 kBJavaScriptView Raw
1'use strict';
2
3var fs = require('fs');
4var path = require('path');
5
6var typeHandlers = require('./types');
7var detector = require('./detector');
8
9// Maximum buffer size, with a default of 512 kilobytes.
10// TO-DO: make this adaptive based on the initial signature of the image
11var MaxBufferSize = 512*1024;
12
13/**
14 * Return size information based on a buffer
15 *
16 * @param {Buffer} buffer
17 * @param {String} filepath
18 * @returns {Object}
19 */
20function lookup (buffer, filepath) {
21 // detect the file type.. don't rely on the extension
22 var type = detector(buffer, filepath);
23
24 // find an appropriate handler for this file type
25 if (type in typeHandlers) {
26 var size = typeHandlers[type].calculate(buffer, filepath);
27 if (size !== false) {
28 size.type = type;
29 return size;
30 }
31 }
32
33 // throw up, if we don't understand the file
34 throw new TypeError('unsupported file type: ' + type + ' (file: ' + filepath + ')');
35}
36
37/**
38 * Reads a file into a buffer.
39 *
40 * The callback will be called after the process has completed. The
41 * callback's first argument will be an error (or null). The second argument
42 * will be the Buffer, if the operation was successful.
43 *
44 * @param {String} filepath
45 * @param {Function} callback
46 */
47function asyncFileToBuffer (filepath, callback) {
48 // open the file in read only mode
49 fs.open(filepath, 'r', function (err, descriptor) {
50 if (err) { return callback(err); }
51 fs.fstat(descriptor, function (err, stats) {
52 if (err) { return callback(err); }
53 var size = stats.size;
54 if (size <= 0) {
55 return callback(new Error('File size is not greater than 0 —— ' + filepath));
56 }
57 var bufferSize = Math.min(size, MaxBufferSize);
58 var buffer = Buffer.alloc(bufferSize);
59 // read first buffer block from the file, asynchronously
60 fs.read(descriptor, buffer, 0, bufferSize, 0, function (err) {
61 if (err) { return callback(err); }
62 // close the file, we are done
63 fs.close(descriptor, function (err) {
64 callback(err, buffer);
65 });
66 });
67 });
68 });
69}
70
71/**
72 * Synchronously reads a file into a buffer, blocking the nodejs process.
73 *
74 * @param {String} filepath
75 * @returns {Buffer}
76 */
77function syncFileToBuffer (filepath) {
78 // read from the file, synchronously
79 var descriptor = fs.openSync(filepath, 'r');
80 var size = fs.fstatSync(descriptor).size;
81 var bufferSize = Math.min(size, MaxBufferSize);
82 var buffer = Buffer.alloc(bufferSize);
83 fs.readSync(descriptor, buffer, 0, bufferSize, 0);
84 fs.closeSync(descriptor);
85 return buffer;
86}
87
88/**
89 * @param {Buffer|string} input - buffer or relative/absolute path of the image file
90 * @param {Function} callback - optional function for async detection
91 */
92module.exports = function (input, callback) {
93
94 // Handle buffer input
95 if (Buffer.isBuffer(input)) {
96 return lookup(input);
97 }
98
99 // input should be a string at this point
100 if (typeof input !== 'string') {
101 throw new TypeError('invalid invocation');
102 }
103
104 // resolve the file path
105 var filepath = path.resolve(input);
106
107 if (typeof callback === 'function') {
108 asyncFileToBuffer(filepath, function (err, buffer) {
109 if (err) { return callback(err); }
110
111 // return the dimensions
112 var dimensions;
113 try {
114 dimensions = lookup(buffer, filepath);
115 } catch (e) {
116 err = e;
117 }
118 callback(err, dimensions);
119 });
120 } else {
121 var buffer = syncFileToBuffer(filepath);
122 return lookup(buffer, filepath);
123 }
124};
125
126module.exports.types = Object.keys(typeHandlers);